Compare commits
577 Commits
v0.6.2
...
release-1.
Author | SHA1 | Date | |
---|---|---|---|
286648574d | |||
317bba395e | |||
541b41b6a1 | |||
91a8be5262 | |||
91e99703b4 | |||
dd7dac3397 | |||
43d4833dd6 | |||
dd1629b5ca | |||
bc8138ce78 | |||
2d568c1dbb | |||
842b62d111 | |||
4f3357e3ec | |||
9ffe91c372 | |||
7e2add413a | |||
004aefd0b7 | |||
00955ba85c | |||
4a79812d15 | |||
9b2f97e4b7 | |||
35cfb756be | |||
2835fccfa4 | |||
31c7f68990 | |||
4e0ca258de | |||
9653854462 | |||
6e95f8bbcb | |||
ce3aa0d5c7 | |||
d5bfc552c4 | |||
bad54a5967 | |||
49b0a89bfe | |||
265df5fbe3 | |||
f089bcf66a | |||
062e5f0bf0 | |||
d932bfcdea | |||
3ef67cb49d | |||
f08ae22dbe | |||
45d316d1ca | |||
4d8fc6ffee | |||
023e413624 | |||
d361186bca | |||
e7d9559d16 | |||
94eecbb123 | |||
777f74ea0b | |||
2b8d47ddd8 | |||
e839b7b368 | |||
1334027a83 | |||
8d3a0a6a9e | |||
7b7ea41f12 | |||
bb5886094e | |||
b076ce9b44 | |||
05f26898f3 | |||
a698f0ee22 | |||
e69854b35f | |||
228995c148 | |||
071e14f9b0 | |||
b08d6271ab | |||
431d31fff6 | |||
a37571c6c5 | |||
6e98006640 | |||
d264e818c3 | |||
d0f740facf | |||
944b5a6152 | |||
b51232fef4 | |||
99f037e210 | |||
c794a48a06 | |||
47d599e8c3 | |||
0a87e838df | |||
e945e38add | |||
6d68abc707 | |||
e80dd0735b | |||
c276681735 | |||
1d723f0834 | |||
1a4b2a2584 | |||
4eb2a7199c | |||
6d5e68fd01 | |||
fed8b23017 | |||
e3329a98a9 | |||
49efbdad76 | |||
9538a5d57b | |||
66dc6c2d0e | |||
81608815ae | |||
ae5ab4a08f | |||
76b6737570 | |||
9210a57500 | |||
8a752b50fa | |||
c38b1a3a3a | |||
73c9c7f244 | |||
0b9f03bb23 | |||
d1c3a017e3 | |||
b200feceed | |||
7958b2ea22 | |||
c0bdf4d3b5 | |||
71efc996e3 | |||
61383dea2d | |||
270cd1cad5 | |||
559e9b564d | |||
d8a56f60ef | |||
10e3b2939a | |||
ba67523278 | |||
f09964cf51 | |||
e4a70a823d | |||
655d86b97a | |||
f2f780115b | |||
b6be8457f7 | |||
1238c19494 | |||
2caf527f67 | |||
43eae7502b | |||
e035146e01 | |||
de3e21629f | |||
d79a3fcec4 | |||
de079cec42 | |||
b33d06eb0c | |||
dfdaa2902a | |||
0173c51c23 | |||
a118127e9c | |||
1f24b39879 | |||
16863755be | |||
b25ac0f52d | |||
5c59295e72 | |||
85893bf58b | |||
722327e4b8 | |||
ab0a981814 | |||
38483d894e | |||
1082e628d1 | |||
74c68224c7 | |||
200697898d | |||
a3eeda3d23 | |||
92073c45ef | |||
81cded618d | |||
84c0bd37ff | |||
4e60feaeab | |||
d6e150a10e | |||
35ceac65f7 | |||
45ffdef845 | |||
55d6ae343d | |||
a69f45e8cd | |||
68c3ae522e | |||
8e2748f23b | |||
f923a79929 | |||
362b15f4d5 | |||
2649045dfe | |||
3d427bdf70 | |||
8b2af3ac36 | |||
113358daea | |||
6927fd35e8 | |||
fb231ff186 | |||
b2fde289b1 | |||
dcc6ffd184 | |||
27e69c38ab | |||
f4b2bfc0d6 | |||
5482d5d7b4 | |||
b2997dcc46 | |||
48ae8acbd6 | |||
a488f8fb14 | |||
ea8da1f7d3 | |||
8ad92a08ea | |||
35c043a0f9 | |||
fce35ac718 | |||
01518896f9 | |||
caf90e35f5 | |||
1f486fd78b | |||
b58d1e28ef | |||
ebb5937568 | |||
ef444fb29c | |||
1ccbaa302c | |||
0d35100eb0 | |||
48316af1d9 | |||
a75fb9a894 | |||
a0ba4b976c | |||
870280a018 | |||
f33df0ef29 | |||
2a087f6f39 | |||
b07d3ab0c3 | |||
f12df92600 | |||
8a75d35c46 | |||
bb28c69cae | |||
25068a4de2 | |||
d2094a0d80 | |||
16dcf4a29c | |||
69a25c9734 | |||
a387a8b06a | |||
a9af97733e | |||
c30674095b | |||
be838b6940 | |||
b0c79a9a1e | |||
8725baa55f | |||
59ab73c57f | |||
7386596bfa | |||
4833ef23e5 | |||
14171bdd3a | |||
d37eba5344 | |||
3b616dae38 | |||
a2758b27e6 | |||
d5c4af7378 | |||
90f37b8183 | |||
1d4f26f325 | |||
08e442a2ab | |||
017dcb39f2 | |||
95121e2f9f | |||
ba11413a6f | |||
e1888df5ab | |||
dceef03633 | |||
443c5d41db | |||
e60171986b | |||
fe45249e9e | |||
b01f017a6d | |||
73bc3ae512 | |||
b6427d3b2b | |||
438024d11b | |||
1d6fdf51dc | |||
281462802f | |||
2b2a86ea2e | |||
c0963596e5 | |||
9be5b241e2 | |||
fcde936670 | |||
73c6bc49c6 | |||
5ed507da83 | |||
ae626b9570 | |||
3528493b92 | |||
9cf460a3b1 | |||
84132ec7bf | |||
eb23260459 | |||
4978424328 | |||
e4cf93665a | |||
3d9367d52a | |||
03b030c56d | |||
a3fe82100b | |||
02d7a690eb | |||
ace0d1ab2e | |||
59d143c1f0 | |||
da2c0520cc | |||
517f520570 | |||
98d2b4c996 | |||
481d425580 | |||
99e988d652 | |||
38a7b4a5b1 | |||
9dc894584d | |||
1a7ab679cd | |||
016baf9984 | |||
b089f2e978 | |||
c3d5ab7bc7 | |||
f13167335a | |||
f0f378c38f | |||
907b44c556 | |||
00011036dd | |||
55497d3931 | |||
c47f206fe3 | |||
386ce0e60a | |||
9fe4172f0d | |||
61f2cdd02b | |||
f87c63da41 | |||
afebbe187d | |||
3951df25be | |||
4b0f175a89 | |||
633a8ada9e | |||
ce723a8c39 | |||
83ace3b486 | |||
23d3c43022 | |||
00470cbfea | |||
4c1abdf2bd | |||
f7842518fb | |||
d756551385 | |||
ced02f5903 | |||
819e3218f6 | |||
c874a159e2 | |||
a68e108333 | |||
da23a8166c | |||
cbb376a137 | |||
3852621bc0 | |||
0ff4cb34ed | |||
d863451771 | |||
78308eea24 | |||
0ab2b8260c | |||
a30bd36a81 | |||
3814396b08 | |||
f88d8a76b0 | |||
6bc1395e15 | |||
6bf538ff40 | |||
c992687200 | |||
9cfa55345e | |||
d9a11a3b8d | |||
2e7d85b85a | |||
dfe6d16353 | |||
1ad1d02e9f | |||
d0996450c7 | |||
b1c4571a95 | |||
3f918d1acb | |||
cadd77776b | |||
72e9c67d05 | |||
62edebad06 | |||
363a39af3e | |||
8b800094af | |||
868005ed0e | |||
07a67a59e7 | |||
955471a064 | |||
b4e2a60cd9 | |||
9467f2e644 | |||
ba66a7896a | |||
74198afa04 | |||
40c39af271 | |||
ecf2ca044e | |||
fd124c82d2 | |||
429b4cd21c | |||
b5f4a66c59 | |||
55690756ae | |||
bbbe89166d | |||
67ac2b9b70 | |||
4b5a5658a6 | |||
9c2bf0197b | |||
e52b5e7f2a | |||
0e14549521 | |||
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
|
||||
|
@ -1,13 +1,12 @@
|
||||
Vreixo Formoso <metalpain2002@yahoo.es>,
|
||||
Mario Danic <mario.danic@gmail.com>,
|
||||
Thomas Schmitt <scdbackup@gmx.net>
|
||||
Copyright (C) 2007-2008 Vreixo Formoso, Mario Danic, Thomas Schmitt
|
||||
Copyright (C) 2007-2011 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 or later
|
||||
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
|
||||
|
263
ChangeLog
263
ChangeLog
@ -1 +1,264 @@
|
||||
libisofs-1.1.2.tar.gz Fri Jul 08 2011
|
||||
===============================================================================
|
||||
* New API call iso_image_get_bootcat()
|
||||
|
||||
libisofs-1.1.0.tar.gz Sat Jun 18 2011
|
||||
===============================================================================
|
||||
* Bug fix: Padding as of iso_write_opts_set_tail_blocks() was added only
|
||||
after cylinder alignment as of iso_write_opts_set_system_area()
|
||||
and thus spoiled this alignment.
|
||||
|
||||
libisofs-1.0.8.tar.gz Thu May 12 2011
|
||||
===============================================================================
|
||||
* Bug fix: iso_write_opts_set_system_area() with system area types
|
||||
1=MIPS Big Endian and 2=MIPS Little Endian caused SIGSEGV.
|
||||
* Bug fix: SIGSEGV if the path given by iso_image_add_mips_boot_file()
|
||||
does not exist in the image at image production time.
|
||||
* Bug fix: While loading an ISO image: Several reads to malloc
|
||||
memory occured with byte index -1. (Found by Valgrind after
|
||||
years of operation without visible problems.)
|
||||
* Bug fix: Closed a memory leak of 32 kB per loaded ISO image.
|
||||
|
||||
libisofs-1.0.6.tar.gz Sat Apr 09 2011
|
||||
===============================================================================
|
||||
* New API call iso_write_opts_set_joliet_long_names()
|
||||
* New error codes for oversized file addresses
|
||||
|
||||
libisofs-1.0.4.tar.gz Thu Mar 10 2011
|
||||
===============================================================================
|
||||
* Bug fix: Compilation failed if --disable-zlib was configured
|
||||
* Bug fix: isohybrid image size was not aligned to cylinder boundary.
|
||||
* New no_md5 value 2 for API call iso_read_opts_set_no_md5()
|
||||
* New option bits 8 and 9 with iso_write_opts_set_system_area()
|
||||
|
||||
libisofs-1.0.2.tar.gz Tue Feb 23 2011
|
||||
===============================================================================
|
||||
* Bug fix: iso_write_opts_set_aaip(opts, 1) could cause fatal miscalculation
|
||||
of the root directory size. This eventually truncated directory
|
||||
tree and spoiled all data file content.
|
||||
* Bug fix: Volume Descriptor Set Terminator contained non-zero bytes in
|
||||
the reserved field (ECMA-119 8.3.4). The bytes stem from the
|
||||
previously written Volume Descriptor.
|
||||
* New API calls iso_tree_clone(), iso_stream_clone.
|
||||
* New IsoFileSourceIface version 2 with method clone_src().
|
||||
* New IsoStreamIface version 4 with method clone_stream().
|
||||
* New public function prototype iso_node_xinfo_cloner.
|
||||
* New API calls iso_node_xinfo_make_clonable(), iso_node_xinfo_get_cloner().
|
||||
* New public iso_node_xinfo_cloner instance aaip_xinfo_cloner().
|
||||
* New API calls iso_node_get_next_xinfo(), iso_node_remove_all_xinfo().
|
||||
* New API call iso_node_remove_tree().
|
||||
* New API call iso_write_opts_set_old_empty().
|
||||
|
||||
libisofs-1.0.0.tar.gz Mon Jan 17 2011
|
||||
===============================================================================
|
||||
* Bug fix: ECMA-119 directory names were truncated to 8 characters if
|
||||
lowercase characters or full ASCII are allowed.
|
||||
* New API call iso_write_opts_set_untranslated_name_len()
|
||||
* New API call iso_write_opts_set_allow_dir_id_ext()
|
||||
* New API call iso_memory_stream_new(). (Was formely a private call.)
|
||||
|
||||
libisofs-0.6.40.tar.gz Fri Dec 10 2010
|
||||
===============================================================================
|
||||
* New API call iso_write_opts_set_disc_label(), new system area type
|
||||
3 = SUN Disk Label for booting SUN SPARC systems.
|
||||
* New API call iso_write_opts_set_will_cancel() avoids start of write thread
|
||||
and is to be used to inquire the future image size.
|
||||
* New error reply code ISO_DISPLACE_ROLLOVER for external data sources with
|
||||
address displacement.
|
||||
|
||||
libisofs-0.6.38.tar.gz Sat Oct 23 2010
|
||||
===============================================================================
|
||||
* New API calls iso_write_opts_attach_jte() and iso_write_opts_detach_jte()
|
||||
allow to use libjte for jigdo production.
|
||||
* New API call iso_write_opts_set_tail_blocks() for tail padding inside
|
||||
ISO image.
|
||||
* New API call iso_image_generator_is_running() to learn when the write thread
|
||||
is done.
|
||||
* New API calls iso_image_add_mips_boot_file(),
|
||||
iso_image_get_mips_boot_files(), iso_image_give_up_mips_boot().
|
||||
* New API call iso_write_opts_set_partition_img() for appending e.g. a small
|
||||
empty FAT12 filesystem which may be used on USB stick.
|
||||
|
||||
libisofs-0.6.36.tar.gz Wed Sep 15 2010
|
||||
===============================================================================
|
||||
* New API function iso_write_opts_set_part_offset() controls creation of
|
||||
an MBR with a first partiton table entry that bears non-zero start address.
|
||||
A second set of volume descriptors and directory tree+tables gets created
|
||||
which can be used to mount the image at the partition start.
|
||||
* Hiding all non-API symbols from the linker by use of --version-script
|
||||
* Automatic C++ detection in libisofs.h by using macro __cplusplus
|
||||
* Corrected several memory leaks and potential NULL pointer evaluations
|
||||
in case of memory shortage.
|
||||
* Now with history of release notes in ./ChangeLog file.
|
||||
|
||||
libisofs-0.6.34.tar.gz Tue Jun 29 2010
|
||||
===============================================================================
|
||||
* New API call iso_image_set_boot_catalog_hidden()
|
||||
* New API call iso_node_get_hidden()
|
||||
* New IsoHideNodeFlag bit LIBISO_HIDE_BUT_WRITE
|
||||
* New error code ISO_BOOT_NO_CATALOG
|
||||
* Opportunity to reduce compile line length by including "config.h"
|
||||
|
||||
libisofs-0.6.32.tar.gz Mon May 03 2010
|
||||
===============================================================================
|
||||
* New API call iso_image_set_boot_catalog_weight()
|
||||
* New API call iso_image_add_boot_image()
|
||||
* New API calls el_torito_set_boot_platform_id(), el_torito_set_id_string(),
|
||||
el_torito_set_selection_crit()
|
||||
* New API calls iso_image_get_all_boot_imgs(), el_torito_get_boot_platform_id(),
|
||||
el_torito_get_load_seg(), el_torito_get_load_size(), el_torito_get_bootable(),
|
||||
el_torito_get_id_string(), el_torito_get_selection_crit(),
|
||||
el_torito_get_isolinux_options(), el_torito_get_boot_media_type()
|
||||
* New API call el_torito_seems_boot_info_table()
|
||||
|
||||
libisofs-0.6.30.tar.gz Sat Apr 17 2010
|
||||
===============================================================================
|
||||
* New API call iso_write_opts_set_system_area() acts like mkisofs option -G.
|
||||
* New API call iso_write_opts_set_pvd_times().
|
||||
* Now able to produce a bootable System Area from an ISOLINUX mbr/isohdp
|
||||
[fp]x*.bin file and an ISOLINUX El Torito bootable image (isolinux.bin).
|
||||
* Now able to produce the same Joliet names as mkisofs.
|
||||
* New API calls iso_read_opts_load_system_area() and
|
||||
iso_image_get_system_area() for multi-session handling of MBRs.
|
||||
|
||||
libisofs-0.6.28.tar.gz Wed Feb 10 2010
|
||||
===============================================================================
|
||||
* Bug fix: Random checksum index could sneak in via boot catalog node
|
||||
and cause a SIGSEGV.
|
||||
* Improved compilability out of the box on FreeBSD.
|
||||
|
||||
libisofs-0.6.26.tar.gz Wed Jan 20 2010
|
||||
===============================================================================
|
||||
* Bug fix: Invalid old checksum tags were preserved with
|
||||
iso_write_opts_set_overwrite_buf(), if the new session produced no checksums.
|
||||
* The checksum buffer for the emerging image gets now marked as invalid if
|
||||
image generation is canceled.
|
||||
* More graceful reaction on filesystems where ACL are not enabled but
|
||||
nevertheless requested by the application.
|
||||
* Adaptions to problems reported by Debian buildd.
|
||||
|
||||
libisofs-0.6.24.tar.gz Thu Oct 08 2009
|
||||
===============================================================================
|
||||
* Bug fix: Short Rock Ridge names got stripped of trailing blanks when loaded
|
||||
and written again to a follow-up session. Long names could lose inner blanks.
|
||||
* Bug fix: Avoided to return NULL or single blanks as content of id strings by
|
||||
API calls iso_image_get_volset_id() ... iso_image_get_biblio_file_id().
|
||||
* New API call iso_write_opts_set_scdbackup_tag().
|
||||
|
||||
libisofs-0.6.22.tar.gz Tue Aug 25 2009
|
||||
===============================================================================
|
||||
* New API call iso_write_opts_set_record_md5() for writing MD5 sums.
|
||||
* New API call iso_read_opts_set_no_md5() for importing MD5 sums.
|
||||
* New API calls iso_image_get_session_md5() and iso_file_get_md5().
|
||||
* New API calls iso_md5_start(), iso_md5_compute(), iso_md5_clone(),
|
||||
iso_md5_end(), iso_md5_match() for own MD5 computations.
|
||||
* New API call iso_util_decode_md5_tag() to recognize and parse checksum tags.
|
||||
* New API call iso_file_make_md5() to equip old file nodes with MD5.
|
||||
* Improvements with ./configure and its help text.
|
||||
|
||||
libisofs-0.6.20.tar.gz Sun May 30 2009
|
||||
===============================================================================
|
||||
* Optional automatic detection and recording of hard link
|
||||
relations between files.
|
||||
* Support for restoring hard link relations by the app.
|
||||
|
||||
libisofs-0.6.18.tar.gz Fri Apr 17 2009
|
||||
===============================================================================
|
||||
* Opportunity to set the input charset automatically from an eventual xattr
|
||||
"isofs.cs" of the image root node.
|
||||
* New general filter API to inquire and remove filters.
|
||||
* Specialized APIs for installing filters which are based on external processes
|
||||
or based on zlib.
|
||||
* New API call to inquire the original source path of a data file in an
|
||||
emerging image.
|
||||
|
||||
libisofs-0.6.16.tar.gz Wed Mar 11
|
||||
===============================================================================
|
||||
* Bug fix: The ".." directory record pointed to the same data block as the "."
|
||||
entry.
|
||||
* Bug fix: The use of iso_write_opts_set_rrip_version_1_10() caused a wrong
|
||||
size announcement in the CE entry which points to the ER signature
|
||||
of the image root.
|
||||
* New API call iso_write_opts_get_data_start() inquires the start address of
|
||||
the data section of an emerging ISO image.
|
||||
* ISO image generation does not absolutely depend on the availability of
|
||||
character set "WCHAR_T" with iconv_open(3) any more.
|
||||
|
||||
libisofs-0.6.14.tar.gz Sat Feb 28 2009
|
||||
===============================================================================
|
||||
* New API calls iso_image_set_ignore_aclea(), iso_read_opts_set_no_aaip()
|
||||
control import of ACL and xattr.
|
||||
* New API calls iso_write_opts_set_aaip(), iso_write_opts_set_aaip_susp_1_10()
|
||||
control output of ACL and xattr into generated ISO image.
|
||||
* New API call iso_file_source_get_aa_string(), new function member
|
||||
get_aa_string() in IsoFileSource_Iface allow to access opaquely encoded ACL
|
||||
and xattr. New function handle aaip_xinfo_func attaches aa_strings to
|
||||
IsoNode objects.
|
||||
* New API calls iso_node_get_acl_text(), iso_node_set_acl_text(),
|
||||
iso_node_get_perms_wo_acl() allow inquiry and manipulation of ACLs in
|
||||
IsoNode objects.
|
||||
* New API calls iso_node_get_attrs(), iso_node_set_attrs() allow inquiry and
|
||||
manipulation of xattr in IsoNode objects.
|
||||
|
||||
libisofs-0.6.12.tar.gz Wed Nov 26 2008
|
||||
===============================================================================
|
||||
* New API calls iso_set_local_charset() and iso_get_local_charset()
|
||||
* New API calls iso_write_opts_set_rrip_version_1_10() and
|
||||
iso_write_opts_set_dir_rec_mtime()
|
||||
* New API call el_torito_set_isolinux_options() allows to patch ISOLINUX boot
|
||||
images and to generate a isohybrid MBR on the fly. Such an MBR makes the ISO
|
||||
image bootable from disk-like hardware, e.g. from USB stick. The ISOLINUX
|
||||
boot image has to be of syslinux 3.72 or later to allow MBR generation.
|
||||
* Old API call el_torito_patch_isolinux_image() is deprecated now.
|
||||
|
||||
libisofs-0.6.10.pl01.tar.gz Wed Nov 19 2008
|
||||
===============================================================================
|
||||
* Bug fix: If images generated by mkisofs were loaded then files of size 0
|
||||
could share their size information with files that contain data. Ticket #144.
|
||||
* Bug fix: ISOLINUX boot images were patched suitable for El Torito but not for
|
||||
an eventual MBR added by SYSLINUX script isohybrid.
|
||||
|
||||
libisofs 0.6.10 Mon Oct 6 2008:
|
||||
===============================================================================
|
||||
* Bug fix: Patching of existing ISOLINUX boot images led to a SIGSEGV.
|
||||
* Bug fix: Adding a new ISOLINUX boot image or patching of an existing one
|
||||
caused a read operation although writing had already begun.
|
||||
|
||||
libisofs-0.6.8.tar.gz Thu Sep 18 2008
|
||||
===============================================================================
|
||||
* Support for very large data files in the ISO 9660 image
|
||||
(Level 3, multi-extent)
|
||||
* Bug fix: it was assumed that isolinux images were always a multiple of 4
|
||||
bytes
|
||||
* New API call iso_image_update_sizes() to refresh recorded file sizes
|
||||
immediately before image generation begins
|
||||
|
||||
libisofs-0.6.6.tar.gz Sun Jun 1 2008
|
||||
===============================================================================
|
||||
* Bug fix: major,minor numbers of device files were not read properly from
|
||||
existing images
|
||||
* Bug fix: iso_tree_path_to_node() returned 1 if a directory path component was
|
||||
a non-directory file
|
||||
* New API call iso_special_get_dev() retrieves major, minor numbers of device
|
||||
files
|
||||
|
||||
libisofs-0.6.4.tar.gz Sun Apr 27 2008
|
||||
===============================================================================
|
||||
* 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
|
||||
|
||||
libisofs-0.6.2.1.tar.gz Thu Feb 14 2008
|
||||
===============================================================================
|
||||
* FIX: missing buffer.h preventing build from succeeding
|
||||
|
||||
Libisofs 0.6.2
|
||||
===============================================================================
|
||||
* Initial release of new generation libisofs
|
||||
* Completely new API
|
||||
* Long term commitment to ABI libisofs.so.6
|
||||
|
||||
|
253
Makefile.am
253
Makefile.am
@ -1,7 +1,12 @@
|
||||
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
|
||||
ACLOCAL_AMFLAGS = -I ./
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
@ -9,6 +14,15 @@ 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.
|
||||
# ts B00927: Eventually enabling use of libjte (Jigdo Template Extraction)
|
||||
libisofs_libisofs_la_CFLAGS = $(LIBACL_DEF) $(XATTR_DEF) $(ZLIB_DEF) \
|
||||
$(LIBJTE_DEF)
|
||||
|
||||
# ts A90114 : added aaip_0_2.*
|
||||
|
||||
libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/builder.h \
|
||||
libisofs/builder.c \
|
||||
@ -16,6 +30,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 +43,11 @@ libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/libiso_msgs.c \
|
||||
libisofs/stream.h \
|
||||
libisofs/stream.c \
|
||||
libisofs/filter.h \
|
||||
libisofs/filter.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 +59,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,93 +68,157 @@ 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/md5.h \
|
||||
libisofs/md5.c
|
||||
libisofs_libisofs_la_LIBADD= \
|
||||
$(THREAD_LIBS)
|
||||
libinclude_HEADERS = \
|
||||
libisofs/libisofs.h
|
||||
|
||||
install-exec-hook:
|
||||
$(LIBBURNIA_LDCONFIG_CMD) "$(DESTDIR)$(libdir)" || echo 'NOTE: Explicite dynamic library configuration failed. If needed, configure manually for:' "$(DESTDIR)$(libdir)"
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
## Build demo applications
|
||||
noinst_PROGRAMS = \
|
||||
demo/lsl \
|
||||
demo/cat \
|
||||
demo/catbuffer \
|
||||
demo/tree \
|
||||
demo/ecma119tree \
|
||||
demo/iso \
|
||||
demo/isoread \
|
||||
demo/isocat \
|
||||
demo/isomodify \
|
||||
demo/isoms \
|
||||
demo/isogrow
|
||||
demo/demo
|
||||
|
||||
demo_lsl_CPPFLAGS = -Ilibisofs
|
||||
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_lsl_SOURCES = demo/lsl.c
|
||||
# demo/tree \
|
||||
# demo/find \
|
||||
# demo/iso \
|
||||
# demo/isoread \
|
||||
# demo/isocat \
|
||||
# demo/isomodify \
|
||||
# demo/isoms
|
||||
|
||||
demo_cat_CPPFLAGS = -Ilibisofs
|
||||
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_cat_SOURCES = demo/cat.c
|
||||
|
||||
demo_catbuffer_CPPFLAGS = -Ilibisofs
|
||||
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_catbuffer_SOURCES = demo/cat_buffer.c
|
||||
|
||||
demo_tree_CPPFLAGS = -Ilibisofs
|
||||
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_tree_SOURCES = demo/tree.c
|
||||
|
||||
demo_ecma119tree_CPPFLAGS = -Ilibisofs
|
||||
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_ecma119tree_SOURCES = demo/ecma119_tree.c
|
||||
|
||||
demo_iso_CPPFLAGS = -Ilibisofs
|
||||
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_iso_SOURCES = demo/iso.c
|
||||
|
||||
demo_isoread_CPPFLAGS = -Ilibisofs
|
||||
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_isoread_SOURCES = demo/iso_read.c
|
||||
|
||||
demo_isocat_CPPFLAGS = -Ilibisofs
|
||||
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_isocat_SOURCES = demo/iso_cat.c
|
||||
|
||||
demo_isomodify_CPPFLAGS = -Ilibisofs
|
||||
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
demo_isomodify_SOURCES = demo/iso_modify.c
|
||||
|
||||
demo_isoms_CPPFLAGS = -Ilibisofs
|
||||
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
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/ecma119tree \
|
||||
# demo/lsl \
|
||||
# demo/cat \
|
||||
# demo/catbuffer \
|
||||
# demo/isogrow
|
||||
|
||||
|
||||
## Build unit test
|
||||
# ts A90807
|
||||
# Consolidated demo code for having less linker mesages with a make run.
|
||||
demo_demo_CPPFLAGS = -Ilibisofs
|
||||
demo_demo_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
|
||||
demo_demo_SOURCES = demo/demo.c
|
||||
|
||||
# ts A90806
|
||||
# This includes fsource.h and thus is no API demo
|
||||
# demo_lsl_CPPFLAGS = -Ilibisofs
|
||||
# demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_lsl_SOURCES = demo/lsl.c
|
||||
|
||||
# ts A90806
|
||||
# This includes fsource.h and thus is no API demo
|
||||
# demo_cat_CPPFLAGS = -Ilibisofs
|
||||
# demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_cat_SOURCES = demo/cat.c
|
||||
|
||||
# ts A90806
|
||||
# This inlcudes buffer.h and thus is no API demo
|
||||
# demo_catbuffer_CPPFLAGS = -Ilibisofs
|
||||
# demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_catbuffer_SOURCES = demo/cat_buffer.c
|
||||
|
||||
# ts A90807
|
||||
# Consolidated in demo/demo
|
||||
# demo_tree_CPPFLAGS = -Ilibisofs
|
||||
# demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_tree_SOURCES = demo/tree.c
|
||||
|
||||
# ts A90807
|
||||
# Consolidated in demo/demo
|
||||
# demo_find_CPPFLAGS = -Ilibisofs
|
||||
# demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_find_SOURCES = demo/find.c
|
||||
|
||||
# ts A90806
|
||||
# This inlcudes lots of internal .h files and thus is no API demo
|
||||
# demo_ecma119tree_CPPFLAGS = -Ilibisofs
|
||||
# demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_ecma119tree_SOURCES = demo/ecma119_tree.c
|
||||
|
||||
# ts A90807
|
||||
# Consolidated in demo/demo
|
||||
# demo_iso_CPPFLAGS = -Ilibisofs
|
||||
# demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_iso_SOURCES = demo/iso.c
|
||||
|
||||
# ts A90807
|
||||
# Consolidated in demo/demo
|
||||
# demo_isoread_CPPFLAGS = -Ilibisofs
|
||||
# demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_isoread_SOURCES = demo/iso_read.c
|
||||
|
||||
# ts A90807
|
||||
# Consolidated in demo/demo
|
||||
# demo_isocat_CPPFLAGS = -Ilibisofs
|
||||
# demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_isocat_SOURCES = demo/iso_cat.c
|
||||
|
||||
# ts A90807
|
||||
# Consolidated in demo/demo
|
||||
# demo_isomodify_CPPFLAGS = -Ilibisofs
|
||||
# demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) \
|
||||
# $(libisofs_libisofs_la_LIBADD)
|
||||
# demo_isomodify_SOURCES = demo/iso_modify.c
|
||||
|
||||
# ts A90807
|
||||
# Consolidated in demo/demo
|
||||
# demo_isoms_CPPFLAGS = -Ilibisofs
|
||||
# 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) \
|
||||
# $(libisofs_libisofs_la_LIBADD) \
|
||||
# -lburn
|
||||
# demo_isogrow_SOURCES = demo/iso_grow.c
|
||||
|
||||
|
||||
## 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 +247,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 +258,17 @@ 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 \
|
||||
doc/checksums.txt \
|
||||
libisofs/libisofs.ver \
|
||||
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
|
||||
|
376
README
376
README
@ -4,15 +4,69 @@
|
||||
|
||||
Released under GPL (see COPYING file for details).
|
||||
|
||||
Copyright (C) 2008 Vreixo Formoso, Mario Danic, Thomas Schmitt
|
||||
Copyright (C) 2008 - 2010 Vreixo Formoso, Mario Danic, Thomas Schmitt
|
||||
|
||||
libisofs is part of the libburnia project (libburnia-project.org)
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
libisofs is a library to create an ISO-9660 filesystem, and supports extensions
|
||||
like RockRidge or Joliet. It is also a full featured ISO-9660 editor, allowing
|
||||
you to modify an ISO image or multisession disc, including file addition and
|
||||
removal, change of file names and attributes, etc
|
||||
Download, Build and Installation
|
||||
|
||||
libisofs code is mantained in a Bazaar repository at Launchpad
|
||||
(https://launchpad.net/libisofs/). You can download it with:
|
||||
|
||||
$ bzr branch lp:libisofs/for-libisoburn
|
||||
|
||||
Our build system is based on autotools. For preparing the build you will need
|
||||
autotools of at least version 1.7. If you have download the code from the
|
||||
repository, first of all you need to execute
|
||||
|
||||
./autogen.sh
|
||||
|
||||
on toplevel dir to execute autotools.
|
||||
|
||||
Alternatively you may unpack a release tarball for which you do not need
|
||||
autotools installed. For the most recent release of libisofs see:
|
||||
http://libburnia-project.org/wiki/Releases
|
||||
|
||||
To build libisofs it should be sufficient to go into its toplevel directory
|
||||
and execute
|
||||
|
||||
./configure --prefix=/usr
|
||||
make
|
||||
|
||||
To make the libraries accessible for running resp. developing applications
|
||||
make install
|
||||
|
||||
On GNU/Linux it will try to run program ldconfig with the library installation
|
||||
directory as only argument. Failure to do so will not abort installation.
|
||||
One may disable ldconfig by ./configure option --disable-ldconfig-at-install .
|
||||
|
||||
By use of a version script, the libisofs.so library exposes no other function
|
||||
names but those of the API definitions in <libisofs/libisofs.h>.
|
||||
If -Wl,--version-script=... makes problems with the local compiler, then
|
||||
disable this encapsulation feature by
|
||||
./configure --disable-versioned-libs
|
||||
make clean ; make
|
||||
|
||||
The ./configure script checks for the availability of supporting libraries.
|
||||
If found, they will become mandatory for the emerging libisofs.so and all
|
||||
applications which use it. This dependency can be avoided by configure options
|
||||
--disable-libacl avoid use of ACL functions like acl_to_text()
|
||||
--disable-xattr avoid use of xattr functions like listxattr()
|
||||
--disable-zlib avoid use of zlib functions like compress2()
|
||||
--disable-libjte avoid use of libjte functions
|
||||
|
||||
See INSTALL file for general options of ./configure.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
libisofs is a library to create an ISO-9660 filesystem, supports extensions
|
||||
like RockRidge or Joliet, and introduces an own extension AAIP.
|
||||
It is a full featured ISO-9660 editor which composes and changes the directory
|
||||
tree of an ISO image. This tree and its newly imported data file contents get
|
||||
then written as independent single-session image or as add-on session for the
|
||||
image from where the tree was originally loaded.
|
||||
|
||||
Features:
|
||||
---------
|
||||
@ -20,32 +74,54 @@ Features:
|
||||
- Image creation
|
||||
- Creates ISO-9660 images from local files.
|
||||
- Support for RockRidge and Joliet extensions.
|
||||
- Support for ISO-9660:1999 (version 2)
|
||||
- Support for El-Torito bootable images.
|
||||
- Full featured edition of file names and attributes on the image.
|
||||
- Several options to relax ISO-9660 constraints.
|
||||
- Special options for images intended for distribution (suitable default
|
||||
modes for files, hiding of real timestamps...)
|
||||
- Multisession
|
||||
- Support for growing an existing image
|
||||
- Support for ISO-9660:1999 (version 2).
|
||||
- Support for El-Torito bootable images. Tested are: PC-BIOS and EFI.
|
||||
- Support for multi-extent data files up to 400 GB (level 3).
|
||||
- Full-featured edition of the image files, including: addition of new
|
||||
files, removing of existent files, moving files, renaming files,
|
||||
change file attributes (permissions, timestamps...)
|
||||
- Support for "emulated multisession" or image growing, suitable for non
|
||||
multisession media such as DVD+RW
|
||||
- Optional recording per file of non-ISO 9660 features:
|
||||
ACL, xattr, content MD5, hard link relations.
|
||||
They do not hamper image readability by operating systems but can be
|
||||
retrieved only via libisofs.
|
||||
- Optional zisofs compression, gzip compression, external filter
|
||||
processes.
|
||||
- Several options to relax ISO-9660 constraints.
|
||||
- Special options for images intended for distribution (suitable
|
||||
default modes for files, hiding of real timestamps...).
|
||||
- Image reading
|
||||
- Image tree and data heap can be verified by stream reading and
|
||||
eventually recorded MD5 tags.
|
||||
- Directory tree and file attributes of ISO 9660 session get loaded
|
||||
into memory for editing or for extraction into local filesystem.
|
||||
- File content can be read by applications.
|
||||
- Automatic zisofs decompression.
|
||||
- Optional application of gzip decompression or external filter
|
||||
processes.
|
||||
- Eventually recorded MD5 of data file can be obtained, MD5 of data
|
||||
stream can be computed and compared.
|
||||
- Helper functions for restoring ACL and/or xattr to the local
|
||||
filesystem.
|
||||
- Multisession
|
||||
- Support for growing an existing image on multi-session media.
|
||||
- Support for "emulated multisession" on overwriteable media such as
|
||||
DVD+RW, USB sticks, regular files.
|
||||
- Support for blindly prepared add-on sessions (mkisofs style -M -C)
|
||||
suitable for pipes which lead to an external burn program.
|
||||
- Image modification
|
||||
- It can create a completely new image from files on another image.
|
||||
- Full-featured edition of image contents
|
||||
- Creates a completely new image from files out of another image and
|
||||
eventual editing operations. Suitable for any target medium.
|
||||
- Others
|
||||
- Handling of different input and output charset
|
||||
- Handling of different input and output charset.
|
||||
- Good integration with libburn for image burning.
|
||||
- Reliable, good handling of different kind of errors.
|
||||
|
||||
Requirements:
|
||||
-------------
|
||||
|
||||
- libburn 0.4.2 headers must be installed at compile time. It is not required
|
||||
at runtime.
|
||||
- iconv() functions for character set conversion must be available.
|
||||
Either implicitely as in Linux or by a separate library like libiconv
|
||||
on FreeBSD.
|
||||
|
||||
Know bugs:
|
||||
----------
|
||||
@ -55,32 +131,20 @@ Multisession and image growing can lead to undesired results in several cases:
|
||||
a) Images with unsupported features, such as:
|
||||
- UDF.
|
||||
- HSF/HFS+ or other Mac extensions.
|
||||
- El-Torito with multiple entries.
|
||||
- ECMA-119 with extended attributes, multiple extends per file.
|
||||
- Non El-Torito boot info.
|
||||
- zisofs compressed images.
|
||||
- ECMA-119 Extended attributes.
|
||||
- ...
|
||||
In all these cases, the resulting new image (or new session) could lack some
|
||||
features of the original image.
|
||||
features of the original image. Nevertheless, the ECMA-119 System Area with
|
||||
an eventual Master Boot Record gets preserved by default.
|
||||
In some cases libisofs will issue warning messages, or even refuse to grow
|
||||
or modify the image. Others remain undetected. Images created with libisofs
|
||||
do not have this problems.
|
||||
|
||||
b) Bootable El-Torito images may have several problems, that result in a new
|
||||
image that is not bootable, or that boots from an outdated session. In many
|
||||
cases it is recommended to add boot info again in the new session.
|
||||
|
||||
- isolinux images won't be bootable after a modify. This is because
|
||||
isolinux images need to have hardcoded the root dir lba. libisofs cannot
|
||||
know whether an image is an isolinux image or not, so the user is
|
||||
responsible to tell libisofs that it must patch the image, with the
|
||||
el_torito_patch_isolinux_image() function. This problem could also exists
|
||||
on other boot images.
|
||||
- Most boot images are highly dependent of the image contents, so if the
|
||||
user moves or removes some files on image it is possible they won't boot
|
||||
anymore.
|
||||
- There is no safer way to modify hidden boot images, as the size of the
|
||||
boot image can't be figured out.
|
||||
b) Bootable El-Torito images may have problems, that result in a new image that
|
||||
is not bootable, or that boots from an outdated session. In some cases it
|
||||
might be necessary to add boot info again in a new first session.
|
||||
- There is no safe way to modify hidden boot images, as the size of the
|
||||
boot image can't be figured out.
|
||||
|
||||
c) Generated images could have different ECMA-119 low level names, due to
|
||||
different way to mangle names, to new files added that force old files to
|
||||
@ -91,210 +155,11 @@ c) Generated images could have different ECMA-119 low level names, due to
|
||||
relaxed contraints), otherwise libisofs might arbitrarily change the names.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Download, Build and Installation
|
||||
|
||||
libisofs code is mantained in a Bazaar repository at Launchpad
|
||||
(https://launchpad.net/libisofs/). You can download it with:
|
||||
|
||||
$ bzr branch lp:libisofs
|
||||
|
||||
Our build system is based on autotools. For preparing the build you will need
|
||||
autotools of at least version 1.7. If you have download the code from the
|
||||
repository, first of all you need to execute
|
||||
|
||||
./autogen.sh
|
||||
|
||||
on toplevel dir to execute autotools.
|
||||
|
||||
Alternatively you may unpack a release tarball for which you do not need
|
||||
autotools installed.
|
||||
|
||||
To build libisofs it should be sufficient to go into its toplevel directory
|
||||
and execute
|
||||
|
||||
./configure --prefix=/usr
|
||||
make
|
||||
|
||||
To make the libraries accessible for running resp. developing applications
|
||||
make install
|
||||
|
||||
See INSTALL file for further details.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Overview of libburnia-project.org
|
||||
|
||||
libburnia-project.org is an open-source software project for reading, mastering
|
||||
and writing optical discs.
|
||||
For now this means only CD media and all single layer DVD media except DVD+R.
|
||||
|
||||
The project comprises of several more or less interdependent parts which
|
||||
together strive to be a usable foundation for application development.
|
||||
These are libraries, language bindings, and middleware binaries which emulate
|
||||
classical (and valuable) Linux tools.
|
||||
|
||||
Our scope is currently Linux 2.4 and 2.6 only. For ports to other systems
|
||||
we would need : login on a development machine resp. a live OS on CD or DVD,
|
||||
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
|
||||
volunteers for testing of realistic use cases.
|
||||
|
||||
We have a workable code base for burning CD and most single layer DVD.
|
||||
The burn API is quite comprehensively documented and can be used to build a
|
||||
presentable application.
|
||||
We have a functional binary which emulates parts of cdrecord in order to
|
||||
prove that usability, and in order to allow you to explore libburnia's scope
|
||||
by help of existing cdrecord frontends.
|
||||
|
||||
The project components (list subject to growth, hopefully):
|
||||
|
||||
- libburn is the library by which preformatted data get onto optical media.
|
||||
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
|
||||
/dev/hdX (e.g. on kernel 2.6).
|
||||
libburn is the foundation of our cdrecord emulation. Its code is
|
||||
independent of cdrecord. Its DVD capabilities are learned from
|
||||
studying the code of dvd+rw-tools and MMC-5 specs. No code but only
|
||||
the pure SCSI knowledge has been taken from dvd+rw-tools, though.
|
||||
|
||||
- libisofs is the library to pack up hard disk files and directories into a
|
||||
ISO 9660 disk image. This may then be brought to media via libburn.
|
||||
libisofs is to be the foundation of our upcoming mkisofs emulation.
|
||||
|
||||
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
|
||||
Cdrecord is a powerful GPL'ed burn program included in Joerg
|
||||
Schilling's cdrtools. cdrskin strives to be a second source for
|
||||
the services traditionally provided by cdrecord. Additionally it
|
||||
provides libburn's DVD capabilities, where only -sao is compatible
|
||||
with cdrecord.
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
||||
Many bytes have been copied from the message output of cdrecord
|
||||
runs, though.
|
||||
See cdrskin/README and man cdrskin/cdrskin.1 for more.
|
||||
|
||||
- test is a collection of application gestures and examples given by the
|
||||
authors of the library features. The main API example for libburn
|
||||
is test/libburner.c .
|
||||
Explore these examples if you look for inspiration.
|
||||
|
||||
We plan to be a responsive upstream. Bear with us. We are still practicing.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Project history as far as known to me:
|
||||
|
||||
- Founded in 2002 as it seems. See mailing list archives
|
||||
http://lists.freedesktop.org/archives/libburn/
|
||||
The site of this founder team is reachable and offers download of a
|
||||
(somewhat outdated) tarball and from CVS :
|
||||
http://icculus.org/burn/
|
||||
Copyright holders and most probably founders:
|
||||
Derek Foreman and Ben Jansens.
|
||||
|
||||
- I came to using libburn in 2005. Founded the cdrskin project and submitted
|
||||
necessary patches which were accepted or implemented better. Except one
|
||||
remaining patch which prevented cdrskin from using vanilla libburn from CVS.
|
||||
The cdrskin project site is reachable and offers download of the heavily
|
||||
patched (elsewise outdated) tarball under the name cdrskin-0.1.2 :
|
||||
http://scdbackup.sourceforge.net/cdrskin_eng.html
|
||||
It has meanwhile moved to use vanilla libburn.pykix.org , though.
|
||||
Version 0.1.4 constitutes the first release of this kind.
|
||||
|
||||
- In July 2006 our team mate Mario Danic announced a revival of libburn
|
||||
which by about nearly everybody else was perceived as unfriendly fork.
|
||||
Derek Foreman four days later posted a message which expressed his
|
||||
discontent.
|
||||
The situation first caused me to publically regret it and then - after i
|
||||
got the opportunity to move in with cdrskin - gave me true reason to
|
||||
personally apologize to Derek Foreman, Ben Jansens and the contibutors at
|
||||
icculus.org/burn. Posted to both projects:
|
||||
http://lists.freedesktop.org/archives/libburn/2006-August/000446.html
|
||||
http://mailman-mail1.webfaction.com/pipermail/libburn-hackers/2006-August/000024.html
|
||||
|
||||
- Mid August 2006 project cdrskin established a branch office in
|
||||
libburn.pykix.org so that all maintainers of our tools have one single place
|
||||
to get the current (at least slightely) usable coordinated versions of
|
||||
everything.
|
||||
Project cdrskin will live forth independendly for a while but it is committed
|
||||
to stay in sync with libburn.pykix.org (or some successor, if ever).
|
||||
cdrskin is also committed to support icculus.org/burn if the pending fork
|
||||
is made reality by content changes in that project. It will cease to maintain
|
||||
a patched version of icculus.org/burn though. Precondition for a new
|
||||
release of cdrskin on base of icculus.org/burn would be the pending
|
||||
"whitelist patch" therefore.
|
||||
I would rather prefer if both projects find consense and merge, or at least
|
||||
cooperate. I have not given up hope totally, yet.
|
||||
I, personally, will honor any approach.
|
||||
|
||||
- 2nd September 2006 the decision is made to strive for a consolidation of
|
||||
copyright and a commitment to GPL in a reasonable and open minded way.
|
||||
This is to avoid long term problems with code of unknown origin and
|
||||
with finding consense among the not so clearly defined group of copyright
|
||||
claimers and -holders.
|
||||
libisofs is already claimed sole copyright Mario Danic.
|
||||
cdrskin and libburner are already claimed sole copyright Thomas Schmitt.
|
||||
Rewrites of other components will follow and concluded by claiming full
|
||||
copyright within the group of libburn.pykix.org-copyright holders.
|
||||
|
||||
- 16th September 2006 feature freeze for release of libburn-0.2.2 .
|
||||
|
||||
- 20th September 2006 release of libburn-0.2.2 .
|
||||
|
||||
- 26th October 2006 feature freeze for cdrskin-0.2.4 based on libburn-0.2.3 .
|
||||
This version of cdrskin is much more cdrecord compatible in repect
|
||||
to drive addressing and audio features.
|
||||
|
||||
- 30th October 2006 release of cdrskin-0.2.4 .
|
||||
|
||||
- 13th November 2006 splitting releases of libburn+cdrskin from libisofs.
|
||||
|
||||
- 24th November 2006 release of libburn-0.2.6 and cdrskin-0.2.6 . cdrskin has
|
||||
become suitable for unaware frontends as long as they perform only the core
|
||||
of cdrecord use cases (including open-ended input streams, audio, and
|
||||
multi-session).
|
||||
|
||||
- 28th November 2006 the umbrella project which encloses both, libisofs and
|
||||
libburn, is now called libburnia. For the origin of this name, see
|
||||
http://en.wikipedia.org/wiki/Liburnians .
|
||||
|
||||
- 16th January 2007 release of libburn-0.3.0 and cdrskin-0.3.0 . Now the scope
|
||||
is widened to a first class of DVD media: overwriteable single layer types
|
||||
DVD-RAM, DVD+RW, DVD-RW. This is not a cdrecord emulation but rather inspired
|
||||
by dvd+rw-tools' "poor man" writing facility for this class of media.
|
||||
Taking a bow towards Andy Polyakov.
|
||||
|
||||
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
|
||||
multi-session and with DAO.
|
||||
|
||||
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
|
||||
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
|
||||
yet.
|
||||
|
||||
- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
|
||||
people that one should not use /dev/sg on kernel 2.6.
|
||||
|
||||
- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
|
||||
We look back on improved stability, a substantially extended list of media
|
||||
and write modes, and better protection against typical user mishaps.
|
||||
|
||||
- 24th October 2007 version 0.4.0 is the foundation of new library libisoburn
|
||||
and an upcomming integrated application for manipulating and writing
|
||||
ISO 9660 + Rock Ridge images. cdrskin-0.4.0 got capabilities like growisofs
|
||||
by these enhancements: growing of overwriteable media and disk files.
|
||||
Taking again a bow towards Andy Polyakov.
|
||||
|
||||
- 26th Januar 2008 version 0.4.2 rectifies the version numbering so that we
|
||||
reliably release libburn.so.4 as should have been done since libburn-0.3.2.
|
||||
cdrskin now is by default linked dynamically and does a runtime check
|
||||
to ensure not to be started with a libburn which is older than itself.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
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. To be exact: version 2 of that License.
|
||||
it under the terms of the GNU General Public License version 2 or later
|
||||
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
|
||||
@ -309,19 +174,19 @@ Project history as far as known to me:
|
||||
Clarification in my name and in the name of Mario Danic, upcoming copyright
|
||||
holders on toplevel of libburnia. To be fully in effect after the remaining
|
||||
other copyrighted code has been replaced by ours and by copyright-free
|
||||
contributions of our friends:
|
||||
contributions of our friends.
|
||||
|
||||
Note:
|
||||
In the particular case of libisofs there is no foreign copyright involved.
|
||||
As of 2010 foreign copyright is only in component libburn.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
We, the copyright holders, agree on the interpretation that
|
||||
dynamical linking of our libraries constitutes "use of" and
|
||||
not "derivation from" our work in the sense of GPL, provided
|
||||
those libraries are compiled from our unaltered code.
|
||||
|
||||
Thus you may link our libraries dynamically with applications
|
||||
which are not under GPL. You may distribute our libraries and
|
||||
application tools in binary form, if you fulfill the usual
|
||||
condition of GPL to offer a copy of the source code -altered
|
||||
or unaltered- under GPL.
|
||||
We will not raise any legal protest to dynamic linking of our libraries
|
||||
with applications that are not under GPL, as long as they fulfill
|
||||
the condition of offering the library source code used, whether
|
||||
altered or unaltered, under the GPLv2+, along with the application.
|
||||
Nevertheless, the safest legal position is not to link libburn with
|
||||
non-GPL compatible programs.
|
||||
|
||||
We ask you politely to use our work in open source spirit
|
||||
and with the due reference to the entire open source community.
|
||||
@ -335,7 +200,10 @@ It is the open source idea of responsible freedom which will be
|
||||
decisive and you will have to prove that you exhausted all own
|
||||
means to qualify for GPL.
|
||||
|
||||
For now we are firmly committed to maintain one single license: GPL.
|
||||
We are firmly committed to allow GPLv2+ now and with future releases.
|
||||
|
||||
signed: Mario Danic, Thomas Schmitt
|
||||
Signed: Mario Danic, Thomas Schmitt
|
||||
Agreement joined later by: Vreixo Formoso
|
||||
|
||||
Public contact: <libburn-hackers@pykix.org>
|
||||
|
||||
|
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
|
||||
|
180
acinclude.m4
180
acinclude.m4
@ -1,22 +1,200 @@
|
||||
AC_DEFUN([LIBBURNIA_SET_FLAGS],
|
||||
[
|
||||
case $target_os in
|
||||
freebsd*)
|
||||
LDFLAGS="$LDFLAGS -L/usr/local/lib"
|
||||
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
|
||||
;;
|
||||
esac
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TARGET_SHIZZLE],
|
||||
[
|
||||
ARCH=""
|
||||
LIBBURNIA_PKGCONFDIR="$libdir"/pkgconfig
|
||||
|
||||
AC_MSG_CHECKING([target operating system])
|
||||
|
||||
LIBBURNIA_LDCONFIG_CMD="echo 'No ldconfig run performed. If needed, configure manually for:'"
|
||||
case $target in
|
||||
*-*-linux*)
|
||||
ARCH=linux
|
||||
LIBBURN_ARCH_LIBS=
|
||||
LIBBURNIA_LDCONFIG_CMD=ldconfig
|
||||
;;
|
||||
*-*-freebsd*)
|
||||
ARCH=freebsd
|
||||
LIBBURN_ARCH_LIBS=-lcam
|
||||
|
||||
# This may later be overridden by configure --enable-libdir-pkgconfig
|
||||
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
|
||||
|
||||
AC_MSG_RESULT([$ARCH])
|
||||
])
|
||||
|
||||
|
||||
dnl LIBBURNIA_CHECK_ICONV is by Thomas Schmitt, libburnia project
|
||||
dnl It is based on gestures from:
|
||||
dnl iconv.m4 serial AM7 (gettext-0.18)
|
||||
dnl Copyright (C) 2000-2002, 2007-2009 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
dnl From Bruno Haible.
|
||||
dnl
|
||||
AC_DEFUN([LIBBURNIA_CHECK_ICONV],
|
||||
[
|
||||
|
||||
dnl Check whether it is allowed to link with -liconv
|
||||
AC_MSG_CHECKING([for iconv() in separate -liconv ])
|
||||
libburnia_liconv="no"
|
||||
libburnia_save_LIBS="$LIBS"
|
||||
LIBS="$LIBS -liconv"
|
||||
AC_TRY_LINK([#include <stdlib.h>
|
||||
#include <iconv.h>],
|
||||
[iconv_t cd = iconv_open("","");
|
||||
iconv(cd,NULL,NULL,NULL,NULL);
|
||||
iconv_close(cd);],
|
||||
[libburnia_liconv="yes"],
|
||||
[LIBS="$libburnia_save_LIBS"]
|
||||
)
|
||||
AC_MSG_RESULT([$libburnia_liconv])
|
||||
|
||||
if test x"$libburnia_save_LIBS" = x"$LIBS"
|
||||
then
|
||||
dnl GNU iconv has no function iconv() but libiconv() and a macro iconv()
|
||||
dnl It is not tested whether this is detected by above macro.
|
||||
AC_CHECK_LIB(iconv, libiconv, , )
|
||||
fi
|
||||
|
||||
dnl Check for iconv(..., const char **inbuf, ...)
|
||||
AC_MSG_CHECKING([for const qualifier with iconv() ])
|
||||
AC_TRY_COMPILE([
|
||||
#include <stdlib.h>
|
||||
#include <iconv.h>
|
||||
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
|
||||
], [], [libburnia_iconv_const=""], [libburnia_iconv_const="const"]
|
||||
)
|
||||
AC_DEFINE_UNQUOTED([ICONV_CONST], [$libburnia_iconv_const])
|
||||
test -z "$libburnia_iconv_const" && libburnia_iconv_const="no"
|
||||
AC_MSG_RESULT([$libburnia_iconv_const])
|
||||
])
|
||||
|
||||
|
||||
dnl LIBBURNIA_ASSERT_ICONV is by Thomas Schmitt, libburnia project
|
||||
dnl
|
||||
AC_DEFUN([LIBBURNIA_ASSERT_ICONV],
|
||||
[
|
||||
if test x$LIBISOFS_ASSUME_ICONV = x
|
||||
then
|
||||
dnl Check for the essential gestures of libisofs/util.c
|
||||
AC_MSG_CHECKING([for iconv() to be accessible now ])
|
||||
AC_TRY_LINK([
|
||||
#include <stdlib.h>
|
||||
#include <wchar.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>],
|
||||
[iconv_t cd = iconv_open("","");
|
||||
iconv(cd,NULL,NULL,NULL,NULL);
|
||||
iconv_close(cd);
|
||||
], [iconv_test="yes"], [iconv_test="no"]
|
||||
)
|
||||
AC_MSG_RESULT([$iconv_test])
|
||||
if test x$iconv_test = xno
|
||||
then
|
||||
echo >&2
|
||||
echo "Cannot get function iconv() to work. Configuration aborted." >&2
|
||||
echo "Check whether your system needs a separate libiconv installed." >&2
|
||||
echo "If it is installed but not found, try something like" >&2
|
||||
echo ' export LDFLAGS="$LDFLAGS -L/usr/local/lib"' >&2
|
||||
echo ' export CPPFLAGS="$CPPFLAGS -I/usr/local/include"' >&2
|
||||
echo ' export LIBS="$LIBS -liconv"' >&2
|
||||
echo "You may override this test by exporting variable" >&2
|
||||
echo " LIBISOFS_ASSUME_ICONV=yes" >&2
|
||||
echo >&2
|
||||
(exit 1); exit 1;
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
dnl LIBISOFS_ASSERT_VERS_LIBS is by Thomas Schmitt, libburnia project
|
||||
dnl It tests whether -Wl,--version-script=... works with the compiler
|
||||
AC_DEFUN([LIBISOFS_ASSERT_VERS_LIBS],
|
||||
[
|
||||
libburnia_save_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS -Wl,--version-script=libisofs/libisofs.ver"
|
||||
AC_TRY_LINK([#include <stdio.h>], [printf("Hello\n");],
|
||||
[vers_libs_test="yes"], [vers_libs_test="no"])
|
||||
if test x$vers_libs_test = xno
|
||||
then
|
||||
LDFLAGS="$libburnia_save_LDFLAGS"
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
dnl LIBBURNIA_SET_PKGCONFIG determines the install directory for the *.pc file.
|
||||
dnl Important: Must be performed _after_ TARGET_SHIZZLE
|
||||
dnl
|
||||
AC_DEFUN([LIBBURNIA_SET_PKGCONFIG],
|
||||
[
|
||||
### for testing --enable-libdir-pkgconfig on Linux
|
||||
### LIBBURNIA_PKGCONFDIR="$libdir"data/pkgconfig
|
||||
|
||||
if test "x$LIBBURNIA_PKGCONFDIR" = "x$libdir"/pkgconfig
|
||||
then
|
||||
dummy=dummy
|
||||
else
|
||||
AC_ARG_ENABLE(libdir-pkgconfig,
|
||||
[ --enable-libdir-pkgconfig Install to $libdir/pkgconfig on any OS, default=no],
|
||||
, enable_libdir_pkgconfig="no")
|
||||
AC_MSG_CHECKING([for --enable-libdir-pkgconfig])
|
||||
if test "x$enable_libdir_pkgconfig" = xyes
|
||||
then
|
||||
LIBBURNIA_PKGCONFDIR="$libdir"/pkgconfig
|
||||
fi
|
||||
AC_MSG_RESULT([$enable_libdir_pkgconfig])
|
||||
fi
|
||||
|
||||
libburnia_pkgconfig_override="no"
|
||||
AC_ARG_ENABLE(pkgconfig-path,
|
||||
[ --enable-pkgconfig-path=DIR Absolute path of directory for libisofs-*.pc],
|
||||
libburnia_pkgconfig_override="yes" , enable_pkgconfig_path="none")
|
||||
AC_MSG_CHECKING([for overridden pkgconfig directory path])
|
||||
if test "x$enable_pkgconfig_path" = xno
|
||||
then
|
||||
libburnia_pkgconfig_override="no"
|
||||
fi
|
||||
if test "x$enable_pkgconfig_path" = x -o "x$enable_pkgconfig_path" = xyes
|
||||
then
|
||||
libburnia_pkgconfig_override="invalid argument"
|
||||
fi
|
||||
if test "x$libburnia_pkgconfig_override" = xyes
|
||||
then
|
||||
LIBBURNIA_PKGCONFDIR="$enable_pkgconfig_path"
|
||||
AC_MSG_RESULT([$LIBBURNIA_PKGCONFDIR])
|
||||
else
|
||||
AC_MSG_RESULT([$libburnia_pkgconfig_override])
|
||||
fi
|
||||
AC_SUBST(LIBBURNIA_PKGCONFDIR)
|
||||
|
||||
dnl For debugging only
|
||||
### AC_MSG_RESULT([LIBBURNIA_PKGCONFDIR = $LIBBURNIA_PKGCONFDIR])
|
||||
|
||||
])
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
aclocal
|
||||
aclocal -I .
|
||||
libtoolize --copy --force
|
||||
autoconf
|
||||
|
||||
# ts A61101 : libburn is not prepared for config.h
|
||||
# autoheader
|
||||
|
||||
automake --foreign --add-missing --copy --include-deps
|
||||
|
145
configure.ac
145
configure.ac
@ -1,17 +1,14 @@
|
||||
AC_INIT([libisofs], [0.6.2], [http://libburnia-project.org])
|
||||
AC_INIT([libisofs], [1.1.2], [http://libburnia-project.org])
|
||||
AC_PREREQ([2.50])
|
||||
dnl AC_CONFIG_HEADER([config.h])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
LIBBURNIA_SET_FLAGS
|
||||
|
||||
dnl A61101 This breaks Linux build (makes 32 bit off_t)
|
||||
dnl http://sourceware.org/autobook/autobook/autobook_96.html says
|
||||
dnl one must include some config.h and this was a pitfall.
|
||||
dnl So why dig the pit at all ?
|
||||
dnl AM_CONFIG_HEADER(config.h)
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
AC_CONFIG_MACRO_DIR([./])
|
||||
|
||||
dnl
|
||||
dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
|
||||
@ -37,13 +34,13 @@ dnl iso_lib_version(). It returns the major, minor and micro revision of the
|
||||
dnl library. This means LIBISOFS_*_VERSION kept its second job which does not
|
||||
dnl comply to the usual ways of configure.ac . I.e. now *officially* this is
|
||||
dnl the source code release version as announced to the public. It has no
|
||||
dnl conection to SONAME or libtool version numbering.
|
||||
dnl connection to SONAME or libtool version numbering.
|
||||
dnl It rather feeds the API function iso_lib_version().
|
||||
dnl
|
||||
dnl If LIBISOFS_*_VERSION changes, be sure to change AC_INIT above to match.
|
||||
dnl
|
||||
LIBISOFS_MAJOR_VERSION=0
|
||||
LIBISOFS_MINOR_VERSION=6
|
||||
LIBISOFS_MAJOR_VERSION=1
|
||||
LIBISOFS_MINOR_VERSION=1
|
||||
LIBISOFS_MICRO_VERSION=2
|
||||
LIBISOFS_VERSION=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION.$LIBISOFS_MICRO_VERSION
|
||||
|
||||
@ -54,10 +51,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
|
||||
# 2011.07.08 development jump has not yet happened
|
||||
# SONAME = 56 - 50 = 6 . Library name = libisofs.6.50.0
|
||||
LT_CURRENT=56
|
||||
LT_AGE=50
|
||||
LT_REVISION=0
|
||||
LT_AGE=0
|
||||
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
|
||||
|
||||
AC_SUBST(LT_RELEASE)
|
||||
@ -84,6 +82,14 @@ 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.
|
||||
LIBBURNIA_CHECK_ICONV
|
||||
|
||||
dnl To abort configuration if iconv() still cannot be compiled
|
||||
LIBBURNIA_ASSERT_ICONV
|
||||
|
||||
|
||||
AC_PROG_LIBTOOL
|
||||
AC_SUBST(LIBTOOL_DEPS)
|
||||
LIBTOOL="$LIBTOOL --silent"
|
||||
@ -121,31 +127,128 @@ TARGET_SHIZZLE
|
||||
AC_SUBST(ARCH)
|
||||
AC_SUBST(LIBBURN_ARCH_LIBS)
|
||||
|
||||
dnl Add compiler-specific flags
|
||||
|
||||
dnl See if the user wants aggressive optimizations of the code
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug Disable aggressive optimizations [default=yes]],
|
||||
[ --enable-debug Disable aggressive optimizations, default=yes],
|
||||
, enable_debug=yes)
|
||||
if test x$enable_debug != xyes; then
|
||||
if test x$GCC = xyes; then
|
||||
CFLAGS="$CFLAGS -O3"
|
||||
CFLAGS="$CFLAGS -fexpensive-optimizations"
|
||||
CFLAGS="-O3 $CFLAGS"
|
||||
CFLAGS="-fexpensive-optimizations $CFLAGS"
|
||||
fi
|
||||
CFLAGS="$CFLAGS -DNDEBUG"
|
||||
CFLAGS="-DNDEBUG $CFLAGS"
|
||||
else
|
||||
if test x$GCC = xyes; then
|
||||
CFLAGS="$CFLAGS -g -pedantic -Wall"
|
||||
CFLAGS="-g -pedantic -Wall -Wextra -Wno-unused-parameter $CFLAGS"
|
||||
fi
|
||||
CFLAGS="$CFLAGS -DDEBUG"
|
||||
CFLAGS="-DDEBUG $CFLAGS"
|
||||
fi
|
||||
|
||||
dnl Verbose debug to make libisofs issue more debug messages
|
||||
AC_ARG_ENABLE(verbose-debug,
|
||||
[ --enable-verbose-debug Enable verbose debug messages [default=no]],
|
||||
[ --enable-verbose-debug Enable verbose debug messages, default=no],
|
||||
AC_DEFINE(LIBISOFS_VERBOSE_DEBUG, 1))
|
||||
|
||||
|
||||
dnl Determine target directory for libisofs-*.pc
|
||||
dnl Important: Must be performed _after_ TARGET_SHIZZLE
|
||||
dnl
|
||||
LIBBURNIA_SET_PKGCONFIG
|
||||
|
||||
|
||||
dnl Add compiler-specific flags
|
||||
|
||||
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 Linking fails on SuSE 9.0 because zlib has compress2() but lacks
|
||||
dnl compressBound(). So compressBound is the more modern thing to test.
|
||||
dnl The empty parameter after "compressBound" causes -lz.
|
||||
ZLIB_DEF="-DLibisofs_with_zliB"
|
||||
AC_CHECK_HEADER(zlib.h, AC_CHECK_LIB(z, compressBound, , ZLIB_DEF= ), ZLIB_DEF= )
|
||||
else
|
||||
ZLIB_DEF=
|
||||
fi
|
||||
AC_SUBST(ZLIB_DEF)
|
||||
|
||||
dnl ts B00927
|
||||
AC_ARG_ENABLE(libjte,
|
||||
[ --enable-libjte Enable use of libjte by libisofs, default=yes],
|
||||
, enable_libjte=yes)
|
||||
if test "x$enable_libjte" = xyes; then
|
||||
LIBJTE_DEF="-DLibisofs_with_libjtE"
|
||||
AC_CHECK_HEADER(libjte/libjte.h, AC_CHECK_LIB(jte, libjte_new, , LIBJTE_DEF= ), LIBJTE_DEF= )
|
||||
else
|
||||
LIBJTE_DEF=
|
||||
fi
|
||||
AC_SUBST(LIBJTE_DEF)
|
||||
|
||||
# Library versioning normally serves a complex purpose.
|
||||
# Since libisofs obeys strict ABI backward compatibility, it needs only the
|
||||
# simple feature to declare function names "global:" or "local:". Only the
|
||||
# global ones are visible to applications at library load time.
|
||||
AC_ARG_ENABLE(versioned-libs,
|
||||
[ --enable-versioned-libs Enable strict symbol encapsulation , default=yes],
|
||||
, enable_versioned_libs=yes)
|
||||
if test x$enable_versioned_libs = xyes; then
|
||||
vers_libs_test=no
|
||||
LIBISOFS_ASSERT_VERS_LIBS
|
||||
if test x$vers_libs_test = xno
|
||||
then
|
||||
echo "disabled strict symbol encapsulation (test failed)"
|
||||
else
|
||||
echo "enabled strict symbol encapsulation"
|
||||
fi
|
||||
else
|
||||
echo "disabled strict symbol encapsulation"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(ldconfig-at-install,
|
||||
[ --enable-ldconfig-at-install On GNU/Linux run ldconfig, default=yes],
|
||||
, ldconfig_at_install=yes)
|
||||
if test x$ldconfig_at_install = xyes; then
|
||||
dummy=dummy
|
||||
else
|
||||
LIBBURNIA_LDCONFIG_CMD="echo 'NOTE: ldconfig is disabled. If needed, configure manually for:'"
|
||||
echo "disabled run of ldconfig during installation on GNU/Linux"
|
||||
fi
|
||||
AC_SUBST(LIBBURNIA_LDCONFIG_CMD)
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
doc/doxygen.conf
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
|
884
demo/demo.c
Normal file
884
demo/demo.c
Normal file
@ -0,0 +1,884 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 - 2009 Vreixo Formoso, 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
static char helptext[][80] = {
|
||||
"",
|
||||
"This is a collection of libisofs gestures which formerly were distinct",
|
||||
"programs. The first argument chooses the gesture:",
|
||||
" -tree absolute_directory_path",
|
||||
" Import a directory and print the resulting iso tree.",
|
||||
" -find absolute_directory_path",
|
||||
" Import a directory, find matching nodes and print the",
|
||||
" resulting iso tree.",
|
||||
" -iso [options] directory output_file",
|
||||
" Create an iso image from a local directory. For options see",
|
||||
" output of -iso -h",
|
||||
" -iso_read image_file",
|
||||
" Output the contents of an iso image.",
|
||||
" -iso_cat image_file path_in_image",
|
||||
" Extract a file from a given ISO image and put out its content",
|
||||
" to stdout. The file is addressed by path_in_image.",
|
||||
" -iso_modify image_file absolute_directory_path output_file",
|
||||
" Load an iso image, add a directory, and write complete image.",
|
||||
" -iso_ms image_lba nwa image_file directory_path output_file",
|
||||
" Load an iso image, add a directory, and write as add-on",
|
||||
" session which shall be appended to the old image.",
|
||||
" image_lba gives the block address of the start of the most",
|
||||
" recent session in the image_file. nwa gives the block address",
|
||||
" where the add-on session will be appended to the image.",
|
||||
"@"
|
||||
};
|
||||
|
||||
|
||||
#define LIBISOFS_WITHOUT_LIBBURN yes
|
||||
#include "libisofs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX Libisofs_default_path_maX
|
||||
#endif
|
||||
|
||||
|
||||
/* ------------------------- from demo/tree.c ----------------------- */
|
||||
|
||||
static void
|
||||
print_permissions(mode_t mode)
|
||||
{
|
||||
char perm[10];
|
||||
|
||||
/* TODO suid, sticky... */
|
||||
|
||||
perm[9] = '\0';
|
||||
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||
perm[7] = mode & S_IWOTH ? 'w' : '-';
|
||||
perm[6] = mode & S_IROTH ? 'r' : '-';
|
||||
perm[5] = mode & S_IXGRP ? 'x' : '-';
|
||||
perm[4] = mode & S_IWGRP ? 'w' : '-';
|
||||
perm[3] = mode & S_IRGRP ? 'r' : '-';
|
||||
perm[2] = mode & S_IXUSR ? 'x' : '-';
|
||||
perm[1] = mode & S_IWUSR ? 'w' : '-';
|
||||
perm[0] = mode & S_IRUSR ? 'r' : '-';
|
||||
printf("[%s]",perm);
|
||||
}
|
||||
|
||||
static void
|
||||
tree_print_dir(IsoDir *dir, int level)
|
||||
{
|
||||
int i;
|
||||
IsoDirIter *iter;
|
||||
IsoNode *node;
|
||||
char *sp;
|
||||
|
||||
sp = calloc(1, level * 2 + 1);
|
||||
|
||||
for (i = 0; i < level * 2; i += 2) {
|
||||
sp[i] = '|';
|
||||
sp[i+1] = ' ';
|
||||
}
|
||||
|
||||
sp[level * 2-1] = '-';
|
||||
sp[level * 2] = '\0';
|
||||
|
||||
iso_dir_get_children(dir, &iter);
|
||||
while (iso_dir_iter_next(iter, &node) == 1) {
|
||||
|
||||
if (ISO_NODE_IS_DIR(node)) {
|
||||
printf("%s+[D] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s\n", iso_node_get_name(node));
|
||||
tree_print_dir(ISO_DIR(node), level+1);
|
||||
} else if (ISO_NODE_IS_FILE(node)) {
|
||||
printf("%s-[F] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s\n", iso_node_get_name(node) );
|
||||
} else if (ISO_NODE_IS_SYMLINK(node)) {
|
||||
printf("%s-[L] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s -> %s \n", iso_node_get_name(node),
|
||||
iso_symlink_get_dest(ISO_SYMLINK(node)) );
|
||||
} else {
|
||||
printf("%s-[C] ", sp);
|
||||
print_permissions(iso_node_get_permissions(node));
|
||||
printf(" %s\n", iso_node_get_name(node) );
|
||||
}
|
||||
}
|
||||
iso_dir_iter_free(iter);
|
||||
free(sp);
|
||||
}
|
||||
|
||||
int gesture_tree(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
IsoImage *image;
|
||||
|
||||
if (argc != 2) {
|
||||
need_abs_path:;
|
||||
fprintf (stderr, "You need to specify a valid absolute path\n");
|
||||
return 1;
|
||||
}
|
||||
if (argv[1][0] != '/')
|
||||
goto need_abs_path;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
printf("================= IMAGE =================\n");
|
||||
tree_print_dir(iso_image_get_root(image), 0);
|
||||
printf("\n\n");
|
||||
|
||||
iso_image_unref(image);
|
||||
iso_finish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- from demo/find.c ----------------------- */
|
||||
|
||||
static void
|
||||
find_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 gesture_find(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
IsoImage *image;
|
||||
|
||||
if (argc != 2) {
|
||||
need_abs_path:;
|
||||
fprintf (stderr, "You need to specify a valid absolute path\n");
|
||||
return 1;
|
||||
}
|
||||
if (argv[1][0] != '/')
|
||||
goto need_abs_path;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
find_print_dir(iso_image_get_root(image));
|
||||
|
||||
iso_image_unref(image);
|
||||
iso_finish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- from demo/iso.c ----------------------- */
|
||||
|
||||
|
||||
static const char * const optstring = "JRIL:b:hV:";
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
void iso_usage(char **argv)
|
||||
{
|
||||
printf("%s [OPTIONS] DIRECTORY OUTPUT\n", argv[0]);
|
||||
}
|
||||
|
||||
void iso_help()
|
||||
{
|
||||
printf(
|
||||
"Options:\n"
|
||||
" -J Add Joliet support\n"
|
||||
" -R Add Rock Ridge support\n"
|
||||
" -I Add ISO 9660:1999 support\n"
|
||||
" -V label Volume Label\n"
|
||||
" -L <num> Set the ISO level (1 or 2)\n"
|
||||
" -b file Specifies a boot image to add to image\n"
|
||||
" -h Print this message\n"
|
||||
);
|
||||
}
|
||||
|
||||
int iso_callback(IsoFileSource *src)
|
||||
{
|
||||
char *path = iso_file_source_get_path(src);
|
||||
printf("CALLBACK: %s\n", path);
|
||||
free(path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int gesture_iso(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
int c;
|
||||
IsoImage *image;
|
||||
struct burn_source *burn_src;
|
||||
unsigned char buf[2048];
|
||||
FILE *fp = NULL;
|
||||
IsoWriteOpts *opts;
|
||||
char *volid = "VOLID";
|
||||
char *boot_img = NULL;
|
||||
int rr = 0, j = 0, iso1999 = 0, level = 1;
|
||||
|
||||
while ((c = getopt(argc, argv, optstring)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
iso_usage(argv);
|
||||
iso_help();
|
||||
goto ex;
|
||||
break;
|
||||
case 'J':
|
||||
j = 1;
|
||||
break;
|
||||
case 'R':
|
||||
rr = 1;
|
||||
break;
|
||||
case 'I':
|
||||
iso1999 = 1;
|
||||
break;
|
||||
case 'L':
|
||||
level = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
boot_img = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
volid = optarg;
|
||||
break;
|
||||
case '?':
|
||||
iso_usage(argv);
|
||||
goto ex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
printf ("Please pass directory from which to build ISO\n");
|
||||
iso_usage(argv);
|
||||
goto ex;
|
||||
}
|
||||
if (argc < 3) {
|
||||
printf ("Please supply output file\n");
|
||||
iso_usage(argv);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
fp = fopen(argv[optind+1], "w");
|
||||
if (fp == NULL) {
|
||||
err(1, "error opening output file");
|
||||
goto ex;
|
||||
}
|
||||
|
||||
result = iso_init();
|
||||
if (result < 0) {
|
||||
printf ("Can't initialize libisofs\n");
|
||||
goto ex;
|
||||
}
|
||||
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||
|
||||
result = iso_image_new(volid, &image);
|
||||
if (result < 0) {
|
||||
printf ("Error creating image\n");
|
||||
goto ex;
|
||||
}
|
||||
iso_tree_set_follow_symlinks(image, 0);
|
||||
iso_tree_set_ignore_hidden(image, 0);
|
||||
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);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
if (boot_img) {
|
||||
/* adds El-Torito boot info. Tunned for isolinux */
|
||||
ElToritoBootImage *bootimg;
|
||||
result = iso_image_set_boot_image(image, boot_img, ELTORITO_NO_EMUL,
|
||||
"/isolinux/boot.cat", &bootimg);
|
||||
if (result < 0) {
|
||||
printf ("Error adding boot image %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
el_torito_set_load_size(bootimg, 4);
|
||||
el_torito_patch_isolinux_image(bootimg);
|
||||
}
|
||||
|
||||
result = iso_write_opts_new(&opts, 0);
|
||||
if (result < 0) {
|
||||
printf ("Cant create write opts, error %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
iso_write_opts_set_iso_level(opts, level);
|
||||
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);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
iso_write_opts_free(opts);
|
||||
|
||||
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
|
||||
result = fwrite(buf, 1, 2048, fp);
|
||||
if (result < 2048) {
|
||||
printf ("Cannot write block. errno= %d\n", errno);
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
burn_src->free_data(burn_src);
|
||||
free(burn_src);
|
||||
|
||||
iso_image_unref(image);
|
||||
iso_finish();
|
||||
return 0;
|
||||
ex:;
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- from demo/iso_read.c ----------------------- */
|
||||
|
||||
|
||||
static void
|
||||
iso_read_print_type(mode_t mode)
|
||||
{
|
||||
switch(mode & S_IFMT) {
|
||||
case S_IFSOCK: printf("[S] "); break;
|
||||
case S_IFLNK: printf("[L] "); break;
|
||||
case S_IFREG: printf("[R] "); break;
|
||||
case S_IFBLK: printf("[B] "); break;
|
||||
case S_IFDIR: printf("[D] "); break;
|
||||
case S_IFIFO: printf("[F] "); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iso_read_print_file_src(IsoFileSource *file)
|
||||
{
|
||||
struct stat info;
|
||||
char *name;
|
||||
iso_file_source_lstat(file, &info);
|
||||
iso_read_print_type(info.st_mode);
|
||||
print_permissions(info.st_mode);
|
||||
printf(" %10.f ", (double) info.st_size);
|
||||
/* printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino); */
|
||||
name = iso_file_source_get_name(file);
|
||||
printf(" %s", name);
|
||||
free(name);
|
||||
if (S_ISLNK(info.st_mode)) {
|
||||
char buf[PATH_MAX];
|
||||
iso_file_source_readlink(file, buf, PATH_MAX);
|
||||
printf(" -> %s\n", buf);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
iso_read_print_dir(IsoFileSource *dir, int level)
|
||||
{
|
||||
int ret, i;
|
||||
IsoFileSource *file;
|
||||
struct stat info;
|
||||
char *sp;
|
||||
|
||||
sp = calloc(1, level * 2 + 1);
|
||||
|
||||
for (i = 0; i < level * 2; i += 2) {
|
||||
sp[i] = '|';
|
||||
sp[i+1] = ' ';
|
||||
}
|
||||
|
||||
sp[level * 2-1] = '-';
|
||||
sp[level * 2] = '\0';
|
||||
|
||||
ret = iso_file_source_open(dir);
|
||||
if (ret < 0) {
|
||||
printf ("Can't open dir %d\n", ret);
|
||||
}
|
||||
while ((ret = iso_file_source_readdir(dir, &file)) == 1) {
|
||||
printf("%s", sp);
|
||||
iso_read_print_file_src(file);
|
||||
ret = iso_file_source_lstat(file, &info);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
iso_read_print_dir(file, level + 1);
|
||||
}
|
||||
iso_file_source_unref(file);
|
||||
}
|
||||
iso_file_source_close(dir);
|
||||
if (ret < 0) {
|
||||
printf ("Can't print dir\n");
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
|
||||
int gesture_iso_read(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
IsoImageFilesystem *fs;
|
||||
IsoDataSource *src;
|
||||
IsoFileSource *root;
|
||||
IsoReadOpts *ropts;
|
||||
|
||||
if (argc != 2) {
|
||||
printf ("You need to specify a valid path\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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");
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = iso_read_opts_new(&ropts, 0);
|
||||
if (result < 0) {
|
||||
fprintf(stderr, "Error creating read options\n");
|
||||
return 1;
|
||||
}
|
||||
result = iso_image_filesystem_new(src, ropts, 1, &fs);
|
||||
iso_read_opts_free(ropts);
|
||||
if (result < 0) {
|
||||
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));
|
||||
printf("System: %s\n", iso_image_fs_get_system_id(fs));
|
||||
printf("Application: %s\n", iso_image_fs_get_application_id(fs));
|
||||
printf("Copyright: %s\n", iso_image_fs_get_copyright_file_id(fs));
|
||||
printf("Abstract: %s\n", iso_image_fs_get_abstract_file_id(fs));
|
||||
printf("Biblio: %s\n", iso_image_fs_get_biblio_file_id(fs));
|
||||
|
||||
printf("\nDIRECTORY TREE\n");
|
||||
printf("==============\n");
|
||||
|
||||
result = fs->get_root(fs, &root);
|
||||
if (result < 0) {
|
||||
printf ("Can't get root %d\n", result);
|
||||
return 1;
|
||||
}
|
||||
/* iso_read_print_file_src(root); */
|
||||
iso_read_print_dir(root, 0);
|
||||
iso_file_source_unref(root);
|
||||
|
||||
fs->close(fs);
|
||||
iso_filesystem_unref((IsoFilesystem*)fs);
|
||||
iso_data_source_unref(src);
|
||||
iso_finish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- from demo/iso_cat.c ----------------------- */
|
||||
|
||||
|
||||
int gesture_iso_cat(int argc, char **argv)
|
||||
{
|
||||
int res, write_ret;
|
||||
IsoFilesystem *fs;
|
||||
IsoFileSource *file;
|
||||
struct stat info;
|
||||
IsoDataSource *src;
|
||||
IsoReadOpts *opts;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: isocat /path/to/image /path/to/file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = iso_init();
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Can't init libisofs\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = iso_data_source_new_from_file(argv[1], &src);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error creating data source\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = iso_read_opts_new(&opts, 0);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error creating read options\n");
|
||||
return 1;
|
||||
}
|
||||
res = iso_image_filesystem_new(src, opts, 1, &fs);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error creating filesystem\n");
|
||||
return 1;
|
||||
}
|
||||
iso_read_opts_free(opts);
|
||||
|
||||
res = fs->get_by_path(fs, argv[2], &file);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Can't get file, err = %d\n", res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = iso_file_source_lstat(file, &info);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Can't stat file, err = %d\n", res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
fprintf(stderr, "Path refers to a directory!!\n");
|
||||
return 1;
|
||||
} else {
|
||||
char buf[1024];
|
||||
res = iso_file_source_open(file);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Can't open file, err = %d\n", res);
|
||||
return 1;
|
||||
}
|
||||
while ((res = iso_file_source_read(file, buf, 1024)) > 0) {
|
||||
write_ret = fwrite(buf, 1, res, stdout);
|
||||
if (write_ret < res) {
|
||||
printf ("Cannot write block to stdout. errno= %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error reading, err = %d\n", res);
|
||||
return 1;
|
||||
}
|
||||
iso_file_source_close(file);
|
||||
}
|
||||
|
||||
iso_file_source_unref(file);
|
||||
iso_filesystem_unref(fs);
|
||||
iso_data_source_unref(src);
|
||||
iso_finish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- from demo/iso_modify.c ----------------------- */
|
||||
|
||||
|
||||
void iso_modify_usage(char **argv)
|
||||
{
|
||||
printf("%s IMAGE DIRECTORY OUTPUT\n", argv[0]);
|
||||
}
|
||||
|
||||
int gesture_iso_modify(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
IsoImage *image;
|
||||
IsoDataSource *src;
|
||||
struct burn_source *burn_src;
|
||||
unsigned char buf[2048];
|
||||
FILE *fp = NULL;
|
||||
IsoWriteOpts *opts;
|
||||
IsoReadOpts *ropts;
|
||||
|
||||
if (argc < 4) {
|
||||
iso_modify_usage(argv);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
fp = fopen(argv[3], "w");
|
||||
if (fp == NULL) {
|
||||
err(1, "error opening output file");
|
||||
goto ex;
|
||||
}
|
||||
|
||||
iso_init();
|
||||
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||
|
||||
/* create the data source to accesss previous image */
|
||||
result = iso_data_source_new_from_file(argv[1], &src);
|
||||
if (result < 0) {
|
||||
printf ("Error creating data source\n");
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* create the image context */
|
||||
result = iso_image_new("volume_id", &image);
|
||||
if (result < 0) {
|
||||
printf ("Error creating image\n");
|
||||
goto ex;
|
||||
}
|
||||
iso_tree_set_follow_symlinks(image, 0);
|
||||
iso_tree_set_ignore_hidden(image, 0);
|
||||
|
||||
/* import previous image */
|
||||
result = iso_read_opts_new(&ropts, 0);
|
||||
if (result < 0) {
|
||||
fprintf(stderr, "Error creating read options\n");
|
||||
goto ex;
|
||||
}
|
||||
result = iso_image_import(image, src, ropts, NULL);
|
||||
iso_read_opts_free(ropts);
|
||||
iso_data_source_unref(src);
|
||||
if (result < 0) {
|
||||
printf ("Error importing previous session %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* add new dir */
|
||||
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[2]);
|
||||
if (result < 0) {
|
||||
printf ("Error adding directory %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* generate a new image with both previous and added contents */
|
||||
result = iso_write_opts_new(&opts, 1);
|
||||
if (result < 0) {
|
||||
printf("Cant create write opts, error %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
/* for isolinux: iso_write_opts_set_allow_full_ascii(opts, 1); */
|
||||
|
||||
result = iso_image_create_burn_source(image, opts, &burn_src);
|
||||
if (result < 0) {
|
||||
printf ("Cant create image, error %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
iso_write_opts_free(opts);
|
||||
|
||||
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
|
||||
result = fwrite(buf, 1, 2048, fp);
|
||||
if (result < 2048) {
|
||||
printf ("Cannot write block. errno= %d\n", errno);
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
burn_src->free_data(burn_src);
|
||||
free(burn_src);
|
||||
|
||||
iso_image_unref(image);
|
||||
iso_finish();
|
||||
return 0;
|
||||
ex:
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- from demo/iso_ms.c ----------------------- */
|
||||
|
||||
|
||||
void iso_ms_usage(char **argv)
|
||||
{
|
||||
printf("%s LSS NWA DISC DIRECTORY OUTPUT\n", argv[0]);
|
||||
}
|
||||
|
||||
int gesture_iso_ms(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
IsoImage *image;
|
||||
IsoDataSource *src;
|
||||
struct burn_source *burn_src;
|
||||
unsigned char buf[2048];
|
||||
FILE *fp = NULL;
|
||||
IsoWriteOpts *opts;
|
||||
IsoReadOpts *ropts;
|
||||
uint32_t ms_block;
|
||||
|
||||
if (argc < 6) {
|
||||
iso_ms_usage(argv);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
if (strcmp(argv[3], argv[5]) == 0) {
|
||||
fprintf(stderr,
|
||||
"image_file and output_file must not be the same file.\n");
|
||||
goto ex;
|
||||
}
|
||||
|
||||
fp = fopen(argv[5], "w");
|
||||
if (!fp) {
|
||||
err(1, "error opening output file");
|
||||
goto ex;
|
||||
}
|
||||
|
||||
iso_init();
|
||||
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||
|
||||
/* create the data source to accesss previous image */
|
||||
result = iso_data_source_new_from_file(argv[3], &src);
|
||||
if (result < 0) {
|
||||
printf ("Error creating data source\n");
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* create the image context */
|
||||
result = iso_image_new("volume_id", &image);
|
||||
if (result < 0) {
|
||||
printf ("Error creating image\n");
|
||||
goto ex;
|
||||
}
|
||||
iso_tree_set_follow_symlinks(image, 0);
|
||||
iso_tree_set_ignore_hidden(image, 0);
|
||||
|
||||
/* import previous image */
|
||||
result = iso_read_opts_new(&ropts, 0);
|
||||
if (result < 0) {
|
||||
fprintf(stderr, "Error creating read options\n");
|
||||
goto ex;
|
||||
}
|
||||
iso_read_opts_set_start_block(ropts, atoi(argv[1]));
|
||||
result = iso_image_import(image, src, ropts, NULL);
|
||||
iso_read_opts_free(ropts);
|
||||
iso_data_source_unref(src);
|
||||
if (result < 0) {
|
||||
printf ("Error importing previous session %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* add new dir */
|
||||
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[4]);
|
||||
if (result < 0) {
|
||||
printf ("Error adding directory %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* generate a multisession image with new contents */
|
||||
result = iso_write_opts_new(&opts, 1);
|
||||
if (result < 0) {
|
||||
printf("Cant create write opts, error %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* round up to 32kb aligment = 16 block */
|
||||
ms_block = atoi(argv[2]);
|
||||
iso_write_opts_set_ms_block(opts, ms_block);
|
||||
iso_write_opts_set_appendable(opts, 1);
|
||||
|
||||
result = iso_image_create_burn_source(image, opts, &burn_src);
|
||||
if (result < 0) {
|
||||
printf ("Cant create image, error %d\n", result);
|
||||
goto ex;
|
||||
}
|
||||
iso_write_opts_free(opts);
|
||||
|
||||
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
|
||||
result = fwrite(buf, 1, 2048, fp);
|
||||
if (result < 2048) {
|
||||
printf ("Cannot write block. errno= %d\n", errno);
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
burn_src->free_data(burn_src);
|
||||
free(burn_src);
|
||||
|
||||
iso_image_unref(image);
|
||||
iso_finish();
|
||||
return 0;
|
||||
ex:;
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- switcher ----------------------- */
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *gesture;
|
||||
int i;
|
||||
|
||||
if (argc < 2) {
|
||||
usage:;
|
||||
fprintf(stderr, "usage: %s gesture [gesture_options]\n", argv[0]);
|
||||
for (i = 0; helptext[i][0] != '@'; i++)
|
||||
fprintf(stderr, "%s\n", helptext[i]);
|
||||
exit(1);
|
||||
}
|
||||
for (gesture = argv[1]; *gesture == '-'; gesture++);
|
||||
if (strcmp(gesture, "tree") == 0) {
|
||||
gesture_tree(argc - 1, &(argv[1]));
|
||||
} else if(strcmp(gesture, "find") == 0) {
|
||||
gesture_find(argc - 1, &(argv[1]));
|
||||
} else if(strcmp(gesture, "iso") == 0) {
|
||||
gesture_iso(argc - 1, &(argv[1]));
|
||||
} else if(strcmp(gesture, "iso_read") == 0) {
|
||||
gesture_iso_read(argc - 1, &(argv[1]));
|
||||
} else if(strcmp(gesture, "iso_cat") == 0) {
|
||||
gesture_iso_cat(argc - 1, &(argv[1]));
|
||||
} else if(strcmp(gesture, "iso_modify") == 0) {
|
||||
gesture_iso_modify(argc - 1, &(argv[1]));
|
||||
} else if(strcmp(gesture, "iso_ms") == 0) {
|
||||
gesture_iso_ms(argc - 1, &(argv[1]));
|
||||
} else {
|
||||
goto usage;
|
||||
}
|
||||
exit(0);
|
||||
}
|
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,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -10,12 +10,18 @@
|
||||
|
||||
#include "libisofs.h"
|
||||
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX Libisofs_default_path_maX
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
print_permissions(mode_t mode)
|
||||
{
|
||||
char perm[10];
|
||||
|
||||
//TODO suid, sticky...
|
||||
/* TODO suid, sticky... */
|
||||
|
||||
perm[9] = '\0';
|
||||
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||
@ -39,7 +45,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,7 +57,8 @@ print_file_src(IsoFileSource *file)
|
||||
iso_file_source_lstat(file, &info);
|
||||
print_type(info.st_mode);
|
||||
print_permissions(info.st_mode);
|
||||
//printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
|
||||
printf(" %10.f ", (double) info.st_size);
|
||||
/* printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino); */
|
||||
name = iso_file_source_get_name(file);
|
||||
printf(" %s", name);
|
||||
free(name);
|
||||
@ -116,7 +123,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 +141,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,16 +156,16 @@ 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);
|
||||
return 1;
|
||||
}
|
||||
//print_file_src(root);
|
||||
/* 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);
|
||||
|
11
demo/lsl.c
11
demo/lsl.c
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
@ -13,6 +14,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX Libisofs_default_path_maX
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Little test program to test filesystem implementations.
|
||||
*
|
||||
|
@ -15,7 +15,7 @@ print_permissions(mode_t mode)
|
||||
{
|
||||
char perm[10];
|
||||
|
||||
//TODO suid, sticky...
|
||||
/* TODO suid, sticky... */
|
||||
|
||||
perm[9] = '\0';
|
||||
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||
|
727
doc/boot_sectors.txt
Normal file
727
doc/boot_sectors.txt
Normal file
@ -0,0 +1,727 @@
|
||||
|
||||
|
||||
|
||||
Collection of Boot Sector Formats for ISO 9660 Images
|
||||
|
||||
|
||||
by Thomas Schmitt - mailto:scdbackup@gmx.net
|
||||
Libburnia project - mailto:libburn-hackers@pykix.org
|
||||
|
||||
This information is collected from various sources. Some is backed by
|
||||
specifications, some is just rumor which happens to work (maybe not even that).
|
||||
|
||||
|
||||
Content
|
||||
|
||||
EL Torito CD booting, for PC-BIOS x86, PowerPC, (old) Mac, EFI.
|
||||
|
||||
MBR, for PC-BIOS x86 from (pseudo-) hard disk
|
||||
- SYSLINUX isohybrid MBR
|
||||
- GRUB2 grub-mkrescue MBR.
|
||||
|
||||
MIPS Volume Header, for MIPS Big Endian, e.g. SGI Indigo2.
|
||||
|
||||
DEC Boot Block, for MIPS Little Endian , e.g. DECstation.
|
||||
|
||||
SUN Disk Label and boot images, for SUN SPARC
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
EL Torito CD booting
|
||||
for PC-BIOS x86, PowerPC, (old) Mac, EFI
|
||||
|
||||
Sources:
|
||||
El Torito, Bootable CD-ROM Format Specification, Version 1.0, 1995
|
||||
which refers to ECMA-119, the standard for ISO 9660 filesystems.
|
||||
libisofs/eltorito.[ch] by Vreixo Formoso.
|
||||
man mkisofs by Joerg Schilling.
|
||||
|
||||
|
||||
ECMA-119 prescribes that the first 32 kB of an ISO 9660 image are System Area
|
||||
with arbitrary content. This prescription is obeyed by PC-BIOS systems only
|
||||
if the ISO 9660 image is presented on CD, DVD or BD media.
|
||||
In this case the El Torito Boot record is the starting point of booting.
|
||||
|
||||
The Boot Record is a ECMA-119 Volume Descriptor which is eventually located
|
||||
at 2 kB block number 17 (decimal). Its content points to the location of the
|
||||
Boot Catalog.
|
||||
The format is described in part by ECMA-119 8.2 "Boot Record" and further
|
||||
specified by El Torito figure 7.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 0 | 0 | Volume Descriptor Type. 0= Boot record
|
||||
1 - 5 | "CD001" | Standard Identifier
|
||||
6 - 6 | 1 | Volume Descriptor Version
|
||||
7 - 38 | el_torito | Boot System Identifier
|
||||
39 - 70 | 0 | Boot Identifier
|
||||
| |
|
||||
71 -2047 | ========== | Boot System Use
|
||||
| |
|
||||
71 - 74 | cataloglba | The 2 kB block number of the Boot Catalog
|
||||
| | as little-endian 32 bit number.
|
||||
| |
|
||||
75 -2047 | 0 | Unused
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
el_torito is the constant string "EL TORITO SPECIFICATION" padded by 9 zeros.
|
||||
cataloglba has to be provided by the file system generator.
|
||||
|
||||
|
||||
The Boot Catalog lists the available boot images which may be prepared for
|
||||
multiple system architectures, called "platforms".
|
||||
It consists of one or more 2 kB blocks. The content is a sequence of fixed
|
||||
format entries, 32 bytes each.
|
||||
The entries are grouped in sections, which assign the entries to a particular
|
||||
system architecture. The booting system will then choose an entry from an
|
||||
appropriate section.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 31 | ========== | Validation Entry
|
||||
| | begins the first section, specifies an architecture
|
||||
32 - 63 | ========== | Initial/Default Entry
|
||||
| | points to a boot image for given architecture
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
Optional:
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
64 - 95 | ========== | Section Header entry
|
||||
| | begins new section, specifies an architecture
|
||||
96 - 127 | ========== | Section Entry
|
||||
| | points to a boot image for given architecture
|
||||
... | .......... | Optional more Section Entries
|
||||
... | .......... | Optional more Section Headers and their Section
|
||||
| | Entries
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
An architecture is refered by a Platform Id number.
|
||||
Defined by El Torito are:
|
||||
0 = "80x86" which is used for standard PCs with Intel x86 or compatible CPU
|
||||
1 = "PowerPC" (possibly for IBM machines with PowerPC CPU)
|
||||
2 = "Mac" (possibly for Apple computers with MC68000 or PowerPC CPU)
|
||||
Further in use by GRUB2 is:
|
||||
0xef = EFI, a competitor resp. successor to PC-BIOS, possibly in use with
|
||||
Intel ia64 Itanium and possibly with newer Apple machines.
|
||||
|
||||
Words resp. numbers are represented are little-endian.
|
||||
|
||||
Validation Entry:
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 0 | 1 | Header Id
|
||||
| |
|
||||
1 - 1 | platform_id| Platform Id. One of: 0, 1, 2, 0xef. See above.
|
||||
| |
|
||||
2 - 3 | 0 | Reserved
|
||||
4 - 27 | manuf_dev | ID string identifies the manufacturer/developer
|
||||
| | (no non-zero examples known yet)
|
||||
| |
|
||||
28 - 29 | checksum | Checksum Word for the Validation Entry.
|
||||
| | The sum of all words in the entry has to be 0.
|
||||
| |
|
||||
30 - 30 | 0x55 |
|
||||
31 - 31 | 0xaa |
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
Initial/Default Entry:
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 0 | boot_indct | Boot Indicator: 0x88 = bootable, 0x00 = not bootable
|
||||
| |
|
||||
1 - 1 | boot_media | Boot Media Type (i.e. media emulated by boot image):
|
||||
| | 0= no emulation , 1= 1.2 MB diskette, 2=1.44 MB,
|
||||
| | 3= 2.88 MB , 4= hard disk
|
||||
| | (About everybody uses 0 = no emulation)
|
||||
| |
|
||||
2 - 3 | load_seg | Load Segment. (meaning unclear)
|
||||
| | "If this value is 0 the system will use the
|
||||
| | traditional segment of 7C0."
|
||||
| | libisofs default is 0
|
||||
| |
|
||||
4 - 4 | sys_type | System Type.
|
||||
| | "Must be a copy of byte 5 from the partition table
|
||||
| | found in the boot image."
|
||||
| | libisofs reads the start the boot image as MBR
|
||||
| | if boot_media == 4. This emulated MBR has a
|
||||
| | partition table from where a byte gets copied.
|
||||
| | Else this byte is 0.
|
||||
| |
|
||||
5 - 5 | 0 | Unused
|
||||
| |
|
||||
6 - 7 | sec_count | Sector Count.
|
||||
| | "the number of virtual/emulated sectors the system
|
||||
| | will store at Load Segment during the initial boot
|
||||
| | procedure."
|
||||
| | libisofs stores 1 for emulated boot_media and a
|
||||
| | user defined value for boot_media == 0. Often: 4.
|
||||
| |
|
||||
8 - 11 | load_rba | Load RBA. The 2 kB block address where the boot
|
||||
| | image file content is located in the ISO 9660 image.
|
||||
| |
|
||||
12 - 31 | 0 | Unused
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
Section Header Entry:
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 0 | head_ind | Header Indicator: 0x90 = more headers follow
|
||||
| | 0x91 = final header, last section
|
||||
| |
|
||||
1 - 1 | platform_id| Platform Id. One of: 0, 1, 2, 0xef. See above.
|
||||
| |
|
||||
2 - 3 | num_entries| Number of entries to follow in this section
|
||||
| |
|
||||
4 - 31 | | ID string identifies the manufacturer/developer
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
Section Entry:
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 0 | boot_indct | Boot Indicator: 0x88 = bootable, 0x00 = not bootable
|
||||
| |
|
||||
1 - 1 | boot_media | Boot Media Type (i.e. media emulated by boot image):
|
||||
| | Bit 0 to 3 govern emulation
|
||||
| | 0= no emulation , 1= 1.2 MB diskette, 2=1.44 MB,
|
||||
| | 3= 2.88 MB , 4= hard disk
|
||||
| | (About everybody uses 0 = no emulation)
|
||||
| | Bit 4 is reserved and must be 0
|
||||
| | Bit 5 "Continuation entry follows" (meaning unclear)
|
||||
| | Might be the indicator for Extension Entries,
|
||||
| | which are not described here.
|
||||
| | Bit 6 "Image contains an ATAPI driver"
|
||||
| | Bit 7 "Image contains SCSI drivers"
|
||||
| |
|
||||
2 - 3 | load_seg | Load Segment. (meaning unclear)
|
||||
| | See above Initial/Default Entry
|
||||
| | libisofs default is 0.
|
||||
4 - 4 | sys_type | System Type.
|
||||
| | See above Initial/Default Entry
|
||||
| | 0 if not emulation == 4.
|
||||
5 - 5 | 0 | Unused
|
||||
| |
|
||||
6 - 7 | sec_count | Sector Count.
|
||||
| | See above Initial/Default Entry
|
||||
| | libisofs stores 1 for emulated boot_media and a
|
||||
| | user defined value for boot_media == 0. Often: 4.
|
||||
| |
|
||||
8 - 11 | load_rba | Load RBA. The 2 kB block address where the boot
|
||||
| | image file content is located in the ISO 9660 image.
|
||||
| |
|
||||
12 - 31 | sel_crit | "Vendor unique selection criteria."
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
The boot image file content is mostly opaque to the ISO 9660 image generator.
|
||||
Nevertheless there is a tradition named "Boot Info Table" which prescribes
|
||||
to write information into byte fields of the boot image file content.
|
||||
There are no general means known how a producer of ISO 9660 images could
|
||||
detect the need for Boot Info Table production.
|
||||
It rather needs a hint from the user who has to know whether the boot image
|
||||
expects a Boot Info Table.
|
||||
The Boot Info Table begins at byte 8 of the boot image content.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
8 - 11 | pvd_lba | Block address of the Primary Volume Descriptor
|
||||
| | This is the session start LBA + 16.
|
||||
| |
|
||||
12 - 15 | file_lba | Block address of the start of the boot image file
|
||||
| | content.
|
||||
| |
|
||||
16 - 19 | file_len | Number of bytes in boot image file content.
|
||||
| |
|
||||
20 - 23 | checksum | Little-endian: The sum of all 32-bit words of the
|
||||
| | file content from byte 64 to file end.
|
||||
| |
|
||||
24 - 63 | 0 | Reserved
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
MBR
|
||||
for PC-BIOS x86 from (pseudo-) hard disk
|
||||
|
||||
Sources:
|
||||
http://en.wikipedia.org/wiki/Master_boot_record
|
||||
Mailing list conversations with H. Peter Anvin and Vladimir Serbinenko.
|
||||
|
||||
|
||||
The candidates for MBR booting will normally use El Torito rather than MBR
|
||||
if the ISO image is presented on CD, DVD, or BD media.
|
||||
The eventual MBR comes into effect if the image is on a media that is
|
||||
interpreted by the BIOS as some kind of hard disk. Usually real hard disks,
|
||||
floppy disks, USB sticks, memory cards.
|
||||
|
||||
An important part of an MBR is the DOS style partition table. It describes up
|
||||
to four primary partitions. There are two formats used for block address:
|
||||
Cylinder/Head/Sector (C/H/S) and Logical Block Address (LBA). Both are based
|
||||
on units of 512 bytes. So MBR_LBA = ISO_LBA * 4.
|
||||
|
||||
For C/H/S, the sector address is broken up into whole cylinders, remaining
|
||||
heads, and remaining sectors + 1. The nomenclature seems to stem from antique
|
||||
drum storage.
|
||||
There are two parameters, sectors_per_head and heads_per_cylinder which are not
|
||||
stored in the MBR. So it is more or less arbitray how to convert a LBA into
|
||||
a C/H/S address and vice versa. For maximum range of C/H/S addresses one
|
||||
may use sectors_per_head = 63 , heads_per_cylinder = 255.
|
||||
|
||||
|
||||
Words are composed little-endian style.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 439 | = opaque = | Code Area filled with bytes for some boot system,
|
||||
| | typically machine code.
|
||||
| |
|
||||
440 - 443 | disk_sgntr | Disc signature, an individual disk id of obscure
|
||||
| | usability.
|
||||
| | (The Code Area might extend up to this field.)
|
||||
| |
|
||||
444 - 445 | 0 | "usually nulls"
|
||||
| | (The Code Area might extend up to this field.)
|
||||
| |
|
||||
446 - 461 | ========== | Partition Table Entry for partition 1
|
||||
| |
|
||||
446 - 446 | status | Governs bootability:
|
||||
| | 0x80 = bootable/active , 0x00 non-bootable/inactive
|
||||
| |
|
||||
447 - 449 | ========== | C/H/S address of partition start
|
||||
447 - 447 | start_head | Heads part of start address.
|
||||
448 - 448 | start_c_s | Bits 0 to 5 : Sectors part of start address.
|
||||
| | Bits 6 to 7 : Bits 8 to 9 of cylinders part.
|
||||
449 - 449 | start_cyl | Lower 8 bits of cylinders part of start address
|
||||
| |
|
||||
450 - 450 | part_type | Partition type indicates the purpose or kind of
|
||||
| | filesystem in the partition.
|
||||
| |
|
||||
451 - 453 | ========== | C/H/S address of last absolute sector in partition
|
||||
451 - 451 | end_head | Heads part of end address.
|
||||
452 - 452 | end_c_s | Bits 0 to 5 : Sectors part of end address.
|
||||
| Values: 1 to 63, not 0.
|
||||
| | Bits 6 to 7 : Bits 8 to 9 of cylinders part.
|
||||
453 - 453 | end_cyl | Lower 8 bits of cylinders part of end address
|
||||
| |
|
||||
454 - 457 | start_lba | LBA of first absolute sector in partiton.
|
||||
| | Block size is 512. Counting starts at 0.
|
||||
| |
|
||||
458 - 461 | num_blocks | Number of sectors in partition.
|
||||
| |
|
||||
462 - 477 | ========== | Partition Table Entry for partition 2
|
||||
| part_entr2 | 16 bytes. Format as with partition 1.
|
||||
| | All 0 means that partition is unused/undefined.
|
||||
| |
|
||||
478 - 493 | ========== | Partition Table Entry for partition 3
|
||||
| part_entr3 | 16 bytes. See above.
|
||||
| |
|
||||
494 - 509 | ========== | Partition Table Entry for partition 4
|
||||
| part_entr4 | 16 bytes. See above.
|
||||
| |
|
||||
510 - 510 | 0x55 | MBR signature
|
||||
511 - 511 | 0xaa | MBR signature
|
||||
| |
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
By tradition the MBR itself and possibly more blocks are not claimed by any
|
||||
partition. But starting the first partition at a non-zero block address causes
|
||||
on Linux a partition device file (e.g. /dev/sdb1) which cannot be used to mount
|
||||
the ISO filesystem.
|
||||
|
||||
libisofs is able to produce a second set of trees and meta data which is
|
||||
suitable for being mounted at start block 16 (ISO) resp. 64 (MBR).
|
||||
See <libisofs/libisofs.h> for call iso_write_opts_set_part_offset()
|
||||
and http://libburnia-project.org/wiki/PartitionOffset for examples with
|
||||
program xorriso.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
SYSLINUX Isohybrid MBR
|
||||
|
||||
Sources:
|
||||
syslinux-3.72/utils/isohybrid , a perl script by H. Peter Anvin = hpa.
|
||||
Mailing list conversations with hpa.
|
||||
|
||||
|
||||
An isohybrid MBR directs the booting BIOS to an ISOLINUX boot image which
|
||||
is also the target of an El Torito boot catalog entry.
|
||||
For that purpose one has to take an MBR template and has to set a few bytes
|
||||
to values which sufficiently describe the ISO image and the boot image file.
|
||||
|
||||
Words are composed little-endian style.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 431 | = opaque = | Syslinux machine code provided by MBR template
|
||||
| |
|
||||
432 - 439 | hd_bootlba | Address of the ISOLINUX boot image file in the
|
||||
| | ISO image. Counted in 512 byte blocks.
|
||||
| |
|
||||
440 - 443 | mbr_id | Random number
|
||||
444 - 445 | 0 | Padding
|
||||
| |
|
||||
446 - 509 | ========== | Partition table
|
||||
| |
|
||||
446 - 461 | part_entry | Partition table entry 1 describing ISO image size
|
||||
| | starting at LBA 0. I.e. contrary to tradition.
|
||||
| | See above for partition table entry format.
|
||||
| |
|
||||
462 - 509 | 0 | Unused partition entries 2 to 4
|
||||
510 - 511 | 0xaa55 | MBR signature
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
hpa about MBR templates and partition table filesystem types:
|
||||
|
||||
"[MBR templates] are available in the Syslinux build tree under the names:
|
||||
mbr/isohdp[fp]x*.bin
|
||||
The default probably should be mbr/isohdppx.bin, but it's ultimately up
|
||||
to the user.
|
||||
[...]
|
||||
Note: the filesystem type is largely arbitrary, in theory it can be any
|
||||
value other than 0x00, 0x05, 0x0f, 0x85, 0xee, or 0xef. 0x17 ("Windows
|
||||
IFS Hidden") seems safeish, some people believe 0x83 (Linux) is better.
|
||||
"
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
GRUB2 grub-mkrescue MBR
|
||||
|
||||
Sources:
|
||||
Mailing list conversations with Vladimir Serbinenko.
|
||||
|
||||
|
||||
The MBR file that is used with GRUB2 script grub-mkrescue needs only a
|
||||
partition table entry which describes the image size.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 445 | = opaque = | GRUB2 machine code provided by MBR template
|
||||
| |
|
||||
446 - 509 | ========== | Partition table
|
||||
| |
|
||||
446 - 461 | part_entry | Partition table entry 1 describing ISO image size
|
||||
| | Peculiar is the start offset of 1 block.
|
||||
| | This prevents mounting of the partition.
|
||||
| | See above for partition table entry format.
|
||||
| |
|
||||
462 - 509 | 0 | Unused partition entries 2 to 4
|
||||
510 - 511 | 0xaa55 | MBR signature
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
Vladimir Serbinenko about the partition table entry:
|
||||
"Currently we use first and not last entry. You need to:
|
||||
1) Zero-fill 446-510
|
||||
2) Put 0x55, 0xAA into 510-512
|
||||
3) Put 0x80 (for bootable partition), 0, 2, 0 (C/H/S of the start), 0xcd
|
||||
(partition type), [3 bytes of C/H/S end], 0x01, 0x00, 0x00, 0x00 (LBA
|
||||
start in little endian), [LBA end in little endian] at 446-462
|
||||
"
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
MIPS Volume Header
|
||||
for MIPS Big Endian, e.g. SGI Indigo2
|
||||
|
||||
Sources:
|
||||
cdrkit-1.1.10/genisoimage/boot-mips.c
|
||||
by Steve McIntyre <steve@einval.com>
|
||||
which refers to
|
||||
genisovh by Florian Lohoff <flo@rfc822.org>
|
||||
and Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
|
||||
who seem to have learned parameter settings from IRIX CD media
|
||||
There are traces in the web which relate this to specs by
|
||||
MIPS Computer Systems, Inc. , 1985
|
||||
Silicon Graphics Computer Systems, Inc. , 2000
|
||||
|
||||
|
||||
The first 512 bytes of the media constitute the Volume Header.
|
||||
Words are composed big-endian style.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 3 | 0x0be5a941 | Magic number
|
||||
4 - 5 | 0 | Root partition number
|
||||
6 - 7 | 0 | Swap partition number
|
||||
8 - 23 | 0 | Name of file to boot (unclear what this means)
|
||||
| |
|
||||
24 - 71 | ========== | Device Parameters
|
||||
| |
|
||||
24 - 24 | 0 | Spiral addressing skew (unclear what this means)
|
||||
25 - 25 | 0 | Words of 0 before header
|
||||
26 - 26 | 0 | Words of 0 between hdr and data
|
||||
27 - 27 | 0 | Spare sectors per cylinder
|
||||
28 - 29 | num_cyl_l | Number of usable cylinder, lower two bytes
|
||||
| | ((iso_size + BYTES_PER_SECTOR - 1) /
|
||||
| | (SECTORS_PER_TRACK * BYTES_PER_SECTOR)) & 0xffff
|
||||
30 - 31 | 0 | Starting head of volume 0
|
||||
32 - 33 | 1 | Number of tracks per cylinder
|
||||
34 - 34 | 0 | Depth of CTQ queue (unclear what this means)
|
||||
35 - 35 | num_cyl_h | Number of usable cylinders, high byte
|
||||
| | ((iso_size + BYTES_PER_SECTOR - 1) /
|
||||
| | (SECTORS_PER_TRACK * BYTES_PER_SECTOR)) >> 16
|
||||
36 - 37 | 0 | unused
|
||||
38 - 39 | 32 | SECTORS_PER_TRACK
|
||||
40 - 41 | 512 | BYTES_PER_SECTOR
|
||||
42 - 43 | 0 | Sector interleave (unclear what this means)
|
||||
44 - 47 | 0x00000034 | Controller characteristics composed from
|
||||
| | DP_RESEEK 0x00000020 /* recalibrate as last resort */
|
||||
| | DP_IGNOREERRORS 0x00000010
|
||||
| | /* transfer data regardless of errors */
|
||||
| | DP_TRKFWD 0x00000004
|
||||
| | /* forward to replacement track */
|
||||
48 - 51 | 0 | Bytes/sec for kernel stats
|
||||
52 - 55 | 0 | Max num retries on data error
|
||||
56 - 59 | 0 | ms per word to xfer, for iostat
|
||||
60 - 71 | 0 | 6 parameter words for xylogics controllers
|
||||
| |
|
||||
72 - 311 | ========== | Volume Directory with 15 entries of 16 bytes each
|
||||
| |
|
||||
72 - 87 | ========== | Volume Directory Entry 1
|
||||
72 - 79 | boot_name | Boot file basename, eventually padded by 0 to lenght 8
|
||||
80 - 83 | boot_block | ISO 9660 LBA of boot file * 4, i.e. in blocks of 512
|
||||
84 - 87 | boot_bytes | File length in bytes
|
||||
| |
|
||||
88 - 311 | see above | Volume Directory Entries 2 to 15
|
||||
| |
|
||||
312 - 504 | ========== | Partition Table with 16 entries of 12 bytes each
|
||||
| |
|
||||
312 - 407 | 0 | Unused partition entries 1 to 8
|
||||
| |
|
||||
408 - 419 | ========== | Partition Table Entry 9 for Volume Header
|
||||
408 - 411 | part_blks | Number of 512 byte blocks in partition
|
||||
| |(iso_size + (BYTES_PER_SECTOR - 1)) / BYTES_PER_SECTOR
|
||||
412 - 415 | 0 | Start block of partition
|
||||
416 - 419 | 0 | PTYPE_VOLHDR = Partition is volume header
|
||||
| |
|
||||
420 - 431 | 0 | Unused partition entry 10
|
||||
| |
|
||||
432 - 443 | ========== | Partition Table Entry 11 for Volume
|
||||
432 - 435 | part_blks | Number of 512 byte blocks in partition
|
||||
| |(iso_size + (BYTES_PER_SECTOR - 1)) / BYTES_PER_SECTOR
|
||||
436 - 439 | 0 | Start block of partition
|
||||
440 - 443 | 6 | PTYPE_VOLUME = Partition is entire volume
|
||||
| |
|
||||
444 - 503 | 0 | Unused partition entries 12 to 16
|
||||
| |
|
||||
504 - 507 | head_chk | Volume header checksum
|
||||
| | The two's complement of bytes 0 to 503 read as big
|
||||
| | endian unsigned 32 bit: sum(words) + head_chk == 0
|
||||
| |
|
||||
508 - 511 | 0 | Volume header end padding
|
||||
| |
|
||||
up to 2048 | 0 | ISO 9660 Block end padding
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
DEC Boot Block
|
||||
for MIPS Little Endian , e.g. DECstation
|
||||
|
||||
Sources:
|
||||
cdrkit-1.1.10/genisoimage/boot-mipsel.c
|
||||
by Steve McIntyre <steve@einval.com>
|
||||
which refers to
|
||||
delo by Florian Lohoff <flo@rfc822.org>
|
||||
and Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
|
||||
cdrkit-1.1.10/include/glibc_elf.h
|
||||
by Steve McIntyre
|
||||
which is based on
|
||||
<elf.h> from GNUC C Library by Free Software Foundation, Inc.
|
||||
|
||||
|
||||
There seems to be only one boot file possible.
|
||||
Some information needs to be read out of the ELF headers of this boot file.
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 7 | 0 | Padding
|
||||
| |
|
||||
8 - 11 | 0x0002757a | Magic number
|
||||
| |
|
||||
12 - 15 | 1 | Mode /* 0: Single extent, 1: Multi extent boot */
|
||||
| |
|
||||
16 - 19 | load_adr | Load address /* Load below kernel */
|
||||
| | Stems from ELF header of boot file.
|
||||
| | See below Elf32_Phdr field p_vaddr.
|
||||
| |
|
||||
20 - 23 | exec_adr | Execution address /* And exec there */
|
||||
| | Stems from ELF header of boot file.
|
||||
| | See below Elf32_Ehdr field e_entry.
|
||||
| |
|
||||
24 - 31 | ========== | Boot Map Entry 1
|
||||
| |
|
||||
24 - 27 | seg_size | Segment size in file. Blocks of 512 bytes.
|
||||
| | Stems from ELF header of boot file.
|
||||
| | (Elf32_Phdr field p_filesz + 511) / 512;
|
||||
| |
|
||||
28 - 31 | seg_start | Segment file offset. Blocks 512 bytes.
|
||||
| | ISO 9660 LBA of boot file * 4 plus offset
|
||||
| | + offset which stems from ELF header of boot file:
|
||||
| | (Elf32_Phdr field p_offset + 511) / 512;
|
||||
| |
|
||||
32 - 431 | ========== | Boot Map Entries 2 to 51
|
||||
| 0 |
|
||||
| |
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
Elf32_Ehdr gets loaded from boot file byte address 0:
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 23 | | ( Magic number, file information )
|
||||
| |
|
||||
24 - 27 | e_entry | /* Entry point virtual address */
|
||||
| = exec_adr | Needed for exec_adr
|
||||
| |
|
||||
28 - 31 | e_phoff | /* Program header table file offset */
|
||||
| | Byte address of Elf32_Phdr
|
||||
| |
|
||||
|
||||
Elf32_Phdr gets loaded from boot file byte_address Elf32_Ehdr.e_phoff :
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 3 | | ( Segment type )
|
||||
| |
|
||||
4 - 7 | p_offset | /* Segment file offset */
|
||||
|-> seg_start| Needed for seg_start
|
||||
| |
|
||||
8 - 11 | p_vaddr | /* Segment virtual address */
|
||||
| =load_adr | Needed for load_adr
|
||||
| |
|
||||
12 - 15 | | (Segment physical address)
|
||||
| |
|
||||
16 - 19 | p_filesz | /* Segment size in file */
|
||||
|-> seg_size | Needed for seg_size
|
||||
| |
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
SUN Disk Label and boot images
|
||||
for SUN SPARC
|
||||
|
||||
Sources:
|
||||
cdrtools-2.01.01a77/mkisofs/sunlabel.h
|
||||
cdrtools-2.01.01a77/mkisofs/mkisofs.8
|
||||
by Joerg Schilling
|
||||
|
||||
|
||||
The Disk Label is written to the first 512 bytes of the image. It can mark
|
||||
8 partitions (slices ) of which the first contains the ISO image. The other
|
||||
7 may contain boot images.
|
||||
Words are composed big-endian style.
|
||||
|
||||
Boot images are provided externally. mkisofs arranges them after the end of
|
||||
the ISO image so that each starts at a cylinder boundary (320 kB).
|
||||
|
||||
There is a mechanism in mkisofs which fills unused partitions by copies of
|
||||
their predecessor in the partition table:
|
||||
"If the special filename ... is used, the actual and all following
|
||||
boot partitions are mapped to the previous partition.
|
||||
If mkisofs is called with -G image -B ... all boot partitions are
|
||||
mapped to the partition that contains the ISO9660 filesystem."
|
||||
|
||||
|
||||
Disk Label components:
|
||||
|
||||
Byte Range | Value | Meaning
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
0 - 127 | label | ASCII Label
|
||||
| | "CD-ROM Disc with Sun sparc boot created by ..."
|
||||
| | mkisofs option -sparc-label
|
||||
| |
|
||||
128 - 263 | ========== | /* vtoc inclusions from AT&T SVr4 */
|
||||
| |
|
||||
128 - 131 | 1 | Layout version
|
||||
132 - 139 | 0 | /* volume name */
|
||||
140 - 141 | 8 | Number of partitions
|
||||
| |
|
||||
142 - 173 | ========== | 8 partition entries of 4 bytes
|
||||
| |
|
||||
142 - 145 | ========== | Entry for partition 1
|
||||
142 - 143 | 4 | ID tag of partition: 4 = User partition
|
||||
144 - 145 | 0x10 | Permissions: 0x10 = read-only
|
||||
| |
|
||||
146 - 149 | ========== | Entry for partition 2
|
||||
146 - 147 | id_tag2 | ID tag of partition:
|
||||
| | 0 = unused
|
||||
| | 2 = Root partition with boot image
|
||||
148 - 149 | perm2 | Permissions:
|
||||
| | 0 = unused
|
||||
| | 0x10 = read-only (if used)
|
||||
| |
|
||||
150 - 173 | ========== | Entries for partition 3 to 8.
|
||||
| | See above: Entry for partition 2
|
||||
| |
|
||||
174 - 175 | 0 | Padding
|
||||
| |
|
||||
176 - 187 | 0 | /* info for mboot */
|
||||
| |
|
||||
188 - 191 | 0x600ddeee | /* to verify vtoc sanity */
|
||||
| |
|
||||
192 - 231 | 0 | Reserved
|
||||
| |
|
||||
232 - 263 | 0 | 8 Timestamps of yet unknown format
|
||||
| |
|
||||
264 - 419 | 0 | Padding
|
||||
| |
|
||||
420 - 443 | ========== | Disk properties
|
||||
| |
|
||||
420 - 421 | 350 | Rotations per minute
|
||||
422 - 423 | 2048 | Number of physical cylinders (fixely 640 MB)
|
||||
424 - 425 | 0 | /* alternates per cylinder */
|
||||
426 - 429 | 0 | /* obsolete */
|
||||
430 - 431 | 1 | /* interleave factor */
|
||||
432 - 433 | 2048 | Number of data cylinders (fixely 640 MB)
|
||||
434 - 435 | 0 | /* # of alternate cylinders */
|
||||
436 - 437 | 1 | Number of heads per cylinder (i.e. 1 cyl = 320 kB)
|
||||
438 - 439 | 640 | Number of sectors per head (i.e. 1 head = 320 kB)
|
||||
440 - 443 | 0 | /* obsolete */
|
||||
| |
|
||||
444 - 507 | ========== | Partition table
|
||||
| |
|
||||
444 - 451 | ========== | Partition table entry #1
|
||||
| |
|
||||
444 - 447 | start_cyl | Start cylinder
|
||||
| |
|
||||
448 - 451 | num_blocks | Number of blocks in partition
|
||||
| |
|
||||
452 - 507 | ========== | Partition table entries #2 to #8
|
||||
| ... | See above Partition table entry #1
|
||||
| |
|
||||
508 - 509 | 0xdabe | Magic Number
|
||||
| |
|
||||
510 - 511 | checksum | The result of exoring 2-byte words 0 to 254
|
||||
| |
|
||||
---------- | ---------- | ----------------------------------------------------
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> ??? HP-PA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
>>> ??? DEC Alpha
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
320
doc/checksums.txt
Normal file
320
doc/checksums.txt
Normal file
@ -0,0 +1,320 @@
|
||||
|
||||
Description of libisofs MD5 checksumming
|
||||
|
||||
by Thomas Schmitt - mailto:scdbackup@gmx.net
|
||||
Libburnia project - mailto:libburn-hackers@pykix.org
|
||||
26 Aug 2009
|
||||
|
||||
|
||||
MD5 is a 128 bit message digest with a very low probability to be the same for
|
||||
any pair of differing data files. It is described in RFC 1321. and can be
|
||||
computed e.g. by program md5sum.
|
||||
|
||||
libisofs can equip its images with MD5 checksums for superblock, directory
|
||||
tree, the whole session, and for each single data file.
|
||||
See libisofs.h, iso_write_opts_set_record_md5().
|
||||
|
||||
The data file checksums get loaded together with the directory tree if this
|
||||
is enabled by iso_read_opts_set_no_md5(). Loaded checksums can be inquired by
|
||||
iso_image_get_session_md5() and iso_file_get_md5().
|
||||
|
||||
Stream recognizable checksum tags occupy exactly one block each. They can
|
||||
be detected by submitting a block to iso_util_decode_md5_tag().
|
||||
|
||||
libisofs has own MD5 computation functions:
|
||||
iso_md5_start(), iso_md5_compute(), iso_md5_clone(), iso_md5_end(),
|
||||
iso_md5_match()
|
||||
|
||||
|
||||
Representation in the Image
|
||||
|
||||
There may be several stream recognizable checksum tags and a compact array
|
||||
of MD5 items at the end of the session. The latter allows to quickly load many
|
||||
file checksums from media with slow random access.
|
||||
|
||||
|
||||
The Checksum Array
|
||||
|
||||
Location and layout of the checksum array is recorded as AAIP attribute
|
||||
"isofs.ca" of the root node.
|
||||
See doc/susp_aaip_2_0.txt for a general description of AAIP and
|
||||
doc/susp_aaip_isofs_names.txt for the layout of "isofs.ca".
|
||||
|
||||
The single data files hold an index to their MD5 checksum in individual AAIP
|
||||
attributes "isofs.cx". Index I means: array base address + 16 * I.
|
||||
|
||||
If there are N checksummed data files then the array consists of N + 2 entries
|
||||
with 16 bytes each.
|
||||
|
||||
Entry number 0 holds a session checksum which covers the range from the session
|
||||
start block up to (but not including) the start block of the checksum area.
|
||||
This range is described by attribute "isofs.ca" of the root node.
|
||||
|
||||
Entries 1 to N hold the checksums of individual data files.
|
||||
|
||||
Entry number N + 1 holds the MD5 checksum of entries 0 to N.
|
||||
|
||||
|
||||
The Checksum Tags
|
||||
|
||||
Because the inquiry of AAIP attributes demands loading of the image tree,
|
||||
there are also checksum tags which can be detected on the fly when reading
|
||||
and checksumming the session from its start point as learned from a media
|
||||
table-of-content.
|
||||
|
||||
The superblock checksum tag is written after the ECMA-119 volume descriptors.
|
||||
The tree checksum tag is written after the ECMA-119 directory entries.
|
||||
The session checksum tag is written after all payload including the checksum
|
||||
array. (Then follows eventual padding.)
|
||||
|
||||
The tags are single lines of printable text at the very beginning of a block
|
||||
of 2048 bytes. They have the following format:
|
||||
|
||||
Tag_id pos=# range_start=# range_size=# [session_start|next=#] md5=# self=#\n
|
||||
|
||||
Tag_id distinguishes the following tag types
|
||||
"libisofs_rlsb32_checksum_tag_v1" Relocated 64 kB superblock tag
|
||||
"libisofs_sb_checksum_tag_v1" Superblock tag
|
||||
"libisofs_tree_checksum_tag_v1" Directory tree tag
|
||||
"libisofs_checksum_tag_v1" Session tag
|
||||
|
||||
A relocated superblock may appear at LBA 0 of an image which was produced for
|
||||
being stored in a disk file or on overwriteable media (e.g. DVD+RW, BD-RE).
|
||||
Typically there is a first session recorded with a superblock at LBA 32 and
|
||||
the next session may follow shortly after its session tag. (Typically at the
|
||||
next block address which is divisible by 32.) Normally no session starts after
|
||||
the address given by parameter session_start=.
|
||||
|
||||
Session oriented media like CD-R[W], DVD+R, BD-R will have no relocated
|
||||
superblock but rather bear a table-of-content on media level (to be inquired
|
||||
by MMC commands).
|
||||
|
||||
|
||||
Example:
|
||||
A relocated superblock which points to the last session. Then the first session
|
||||
which starts at Logical Block Address 32. The following sessions have the same
|
||||
structure as the first one.
|
||||
|
||||
LBA 0:
|
||||
<... ECMA-119 System Area and Volume Descriptors ...>
|
||||
LBA 18:
|
||||
libisofs_rlsb32_checksum_tag_v1 pos=18 range_start=0 range_size=18 session_start=311936 md5=6fd252d5b1db52b3c5193447081820e4 self=526f7a3c7fefce09754275c6b924b6d9
|
||||
<... padding up to LBA 32 ...>
|
||||
LBA 32:
|
||||
<... First Session: ECMA-119 System Area and Volume Descriptors ...>
|
||||
libisofs_sb_checksum_tag_v1 pos=50 range_start=32 range_size=18 md5=17471035f1360a69eedbd1d0c67a6aa2 self=52d602210883eeababfc9cd287e28682
|
||||
<... ECMA-119 Directory Entries (the tree of file names) ...>
|
||||
LBA 334:
|
||||
libisofs_tree_checksum_tag_v1 pos=334 range_start=32 range_size=302 md5=41acd50285339be5318decce39834a45 self=fe100c338c8f9a494a5432b5bfe6bf3c
|
||||
<... Data file payload and checksum array ...>
|
||||
LBA 81554:
|
||||
libisofs_checksum_tag_v1 pos=81554 range_start=32 range_size=81522 md5=8adb404bdf7f5c0a078873bb129ee5b9 self=57c2c2192822b658240d62cbc88270cb
|
||||
|
||||
<... more sessions ...>
|
||||
|
||||
LBA 311936:
|
||||
<... Last Session: ECMA-119 System Area and Volume Descriptors ...>
|
||||
LBA 311954:
|
||||
libisofs_sb_checksum_tag_v1 pos=311954 range_start=311936 range_size=18 next=312286 md5=7f1586e02ac962432dc859a4ae166027 self=2c5fce263cd0ca6984699060f6253e62
|
||||
<... Last Session: tree, tree checksum tag, data payload, session tag ...>
|
||||
|
||||
|
||||
There are several tag parameters. Addresses are given as decimal numbers, MD5
|
||||
checksums as strings of 32 hex digits.
|
||||
|
||||
pos=
|
||||
gives the block address where the tag supposes itself to be stored.
|
||||
If this does not match the block address where the tag is found then this
|
||||
either indicates that the tag is payload of the image or that the image has
|
||||
been relocated. (The latter makes the image unusable.)
|
||||
|
||||
range_start=
|
||||
The block address where the session is supposed to start. If this does not
|
||||
match the session start on media then the volume descriptors of the
|
||||
image have been relocated. (This can happen with overwriteable media. If
|
||||
checksumming started at LBA 0 and finds range_start=32, then one has to
|
||||
restart checksumming at LBA 32. See libburn/doc/cookbook.txt
|
||||
"ISO 9660 multi-session emulation on overwriteable media" for background
|
||||
information.)
|
||||
|
||||
range_size=
|
||||
The number of blocks beginning at range_start which are covered by the
|
||||
checksum of the tag.
|
||||
|
||||
Only with superblock tag and tree tag:
|
||||
next=
|
||||
The block address where the next tag is supposed to be found. This is
|
||||
to avoid the small possibility that a checksum tag with matching position
|
||||
is part of a directory entry or data file. The superblock tag is quite
|
||||
uniquely placed directly after the ECMA-119 Volume Descriptor Set Terminator
|
||||
where no such cleartext is supposed to reside by accident.
|
||||
|
||||
Only with relocated 64 kB superblock tag:
|
||||
session_start=
|
||||
The start block address (System Area) of the session to which the relocated
|
||||
superblock points.
|
||||
|
||||
md5=
|
||||
The checksum payload of the tag as lower case hex digits.
|
||||
|
||||
self=
|
||||
The MD5 checksum of the tag itself up to and including the last hex digit of
|
||||
parameter "md5=".
|
||||
|
||||
The newline character at the end is mandatory. After that newline there may
|
||||
follow more lines. Their meaning is not necessarily described in this document.
|
||||
|
||||
One such line type is the scdbackup checksum tag, an ancestor of libisofs tags
|
||||
which is suitable only for single session images which begin at LBA 0. It bears
|
||||
a checksum record which by its MD5 covers all bytes from LBA 0 up to the
|
||||
newline character preceding the scdbackup tag. See scdbackup/README appendix
|
||||
VERIFY for details.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Usage at Read Time
|
||||
|
||||
Checking Before Image Tree Loading
|
||||
|
||||
In order to check for a trustworthy loadable image tree, read the first 32
|
||||
blocks from to the session start and look in block 16 to 32 for a superblock
|
||||
checksum tag by
|
||||
iso_util_decode_md5_tag(block, &tag_type, &pos,
|
||||
&range_start, &range_size, &next_tag, md5, 0);
|
||||
|
||||
If a tag of type 2 or 4 appears and has plausible parameters, then check
|
||||
whether its MD5 matches the MD5 of the data blocks which were read before.
|
||||
|
||||
With tag type 2:
|
||||
|
||||
Keep the original MD5 context of the data blocks and clone one for obtaining
|
||||
the MD5 bytes.
|
||||
If the MD5s match, then compute the checksum block and all folowing ones into
|
||||
the kept MD5 context and go on with reading and computing for the tree checksum
|
||||
tag. This will be found at block address next_tag, verified and parsed by:
|
||||
iso_util_decode_md5_tag(block, &tag_type, &pos,
|
||||
&range_start, &range_size, &next_tag, md5, 3);
|
||||
|
||||
Again, if the parameters match the reading state, the MD5 must match the
|
||||
MD5 computed from the data blocks which were before.
|
||||
If so, then the tree is ok and safe to be loaded by iso_image_import().
|
||||
|
||||
With tag type 4:
|
||||
|
||||
End the MD5 context and start a new context for the session which you will
|
||||
read next.
|
||||
|
||||
Then look for the actual session by starting to read at the address given by
|
||||
parameter session_start= which is returned by iso_util_decode_md5_tag() as
|
||||
next_tag. Go on by looking for tag type 2 and follow above prescription.
|
||||
|
||||
|
||||
Checking the Data Part of the Session
|
||||
|
||||
In order to check the trustworthyness of a whole session, continue reading
|
||||
and checksumming after the tree was verified.
|
||||
|
||||
Read and checksum the blocks. When reaching block address next_tag (from the
|
||||
tree tag) submit this block to
|
||||
|
||||
iso_util_decode_md5_tag(block, &tag_type, &pos,
|
||||
&range_start, &range_size, &next_tag, md5, 1);
|
||||
|
||||
If this returns 1, then check whether the returned parameters pos, range_start,
|
||||
and range_size match the state of block reading, and whether the returned
|
||||
bytes in parameter md5 match the MD5 computed from the data blocks which were
|
||||
read before the tag block.
|
||||
|
||||
|
||||
Checking All Sessions
|
||||
|
||||
If the media is sequentially recordable, obtain a table of content and check
|
||||
the first track of each session as prescribed above in Checking Before Image
|
||||
Tree Loading and in Checking the Data Part of the Session.
|
||||
|
||||
With disk files or overwriteable media, look for a relocated superblock tag
|
||||
but do not hop to address next_tag (given by session_start=). Instead look at
|
||||
LBA 32 for the first session and check it as prescribed above.
|
||||
After reaching its end, round up the read address to the next multiple of 32
|
||||
and check whether it is smaller than session_start= from the super block.
|
||||
If so, expect another session to start there.
|
||||
|
||||
|
||||
Checking Single Files in a Loaded Image
|
||||
|
||||
An image may consist of many sessions wherein many data blocks may not belong
|
||||
to files in the directory tree of the most recent session. Checking this
|
||||
tree and all its data files can ensure that all actually valid data in the
|
||||
image are trustworthy. This will leave out the trees of the older sessions
|
||||
and the obsolete data blocks of overwritten or deleted files.
|
||||
|
||||
Once the image has been loaded, you can obtain MD5 sums from IsoNode objects
|
||||
which fulfill
|
||||
iso_node_get_type(node) == LIBISO_FILE
|
||||
|
||||
The recorded checksum can be obtained by
|
||||
iso_file_get_md5(image, (IsoFile *) node, md5, 0);
|
||||
|
||||
For accessing the file data in the loaded image use
|
||||
iso_file_get_stream((IsoFile *) node);
|
||||
to get the data stream of the object.
|
||||
The checksums cover the data content as it was actually written into the ISO
|
||||
image stream, not necessarily as it was on hard disk before or afterwards.
|
||||
This implies that content filtered files bear the MD5 of the filtered data
|
||||
and not of the original files on disk. When checkreading, one has to avoid
|
||||
any reverse filtering. Dig out the stream which directly reads image data
|
||||
by calling iso_stream_get_input_stream() until it returns NULL and use
|
||||
iso_stream_get_size() rather than iso_file_get_size().
|
||||
|
||||
Now you may call iso_stream_open(), iso_stream_read(), iso_stream_close()
|
||||
for reading file content from the loaded image.
|
||||
|
||||
|
||||
Session Check in a Loaded Image
|
||||
|
||||
iso_image_get_session_md5() gives start LBA and session payload size as of
|
||||
"isofs.ca" and the session checksum as of the checksum array.
|
||||
|
||||
For reading you may use the IsoDataSource object which you submitted
|
||||
to iso_image_import() when reading the image. If this source is associated
|
||||
to a libburn drive, then libburn function burn_read_data() can read directly
|
||||
from it.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
scdbackup Checksum Tags
|
||||
|
||||
The session checksum tag does not occupy its whole block. So there is room to
|
||||
store a scdbackup stream checksum tag, which is an ancestor format of the tags
|
||||
described here. This feature allows scdbackup to omit its own checksum filter
|
||||
if using xorriso as ISO 9660 formatter program.
|
||||
Such a tag makes only sense if the session begins at LBA 0.
|
||||
|
||||
See scdbackup-*/README, appendix VERIFY for a specification.
|
||||
|
||||
Example of a scdbackup checksum tag:
|
||||
scdbackup_checksum_tag_v0.1 2456606865 61 2_2 B00109.143415 2456606865 485bbef110870c45754d7adcc844a72c c2355d5ea3c94d792ff5893dfe0d6d7b
|
||||
|
||||
The tag is located at byte position 2456606865, contains 61 bytes of scdbackup
|
||||
checksum record (the next four words):
|
||||
Name of the backup volume is "2_2".
|
||||
Written in year B0 = 2010 (A9 = 2009, B1 = 2011), January (01), 9th (09),
|
||||
14:34:15 local time.
|
||||
The size of the volume is 2456606865 bytes, which have a MD5 sum of
|
||||
485bbef110870c45754d7adcc844a72c.
|
||||
The checksum of "2_2 B00109.143415 2456606865 485bbef110870c45754d7adcc844a72c"
|
||||
is c2355d5ea3c94d792ff5893dfe0d6d7b.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This text is under
|
||||
Copyright (c) 2009 - 2010 Thomas Schmitt <scdbackup@gmx.net>
|
||||
It shall only be modified in sync with libisofs and other software which
|
||||
makes use of libisofs checksums. Please mail change requests to mailing list
|
||||
<libburn-hackers@pykix.org> or to the copyright holder in private.
|
||||
Only if you cannot reach the copyright holder for at least one month it is
|
||||
permissible to modify this text under the same license as the affected
|
||||
copy of libisofs.
|
||||
If you do so, you commit yourself to taking reasonable effort to stay in
|
||||
sync with the other interested users of this text.
|
||||
|
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)
|
||||
|
||||
|
@ -154,13 +154,6 @@ QT_AUTOBRIEF = NO
|
||||
|
||||
MULTILINE_CPP_IS_BRIEF = YES
|
||||
|
||||
# If the DETAILS_AT_TOP tag is set to YES then Doxygen
|
||||
# will output the detailed description near the top, like JavaDoc.
|
||||
# If set to NO, the detailed description appears after the member
|
||||
# documentation.
|
||||
|
||||
DETAILS_AT_TOP = YES
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||
# member inherits the documentation from any documented member that it
|
||||
# re-implements.
|
||||
@ -1150,7 +1143,8 @@ HIDE_UNDOC_RELATIONS = YES
|
||||
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
||||
# have no effect if this option is set to NO (the default)
|
||||
|
||||
HAVE_DOT = YES
|
||||
# ts B10415: dot causes sigsegv on Debian buildd
|
||||
HAVE_DOT = NO
|
||||
|
||||
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
|
456
doc/susp_aaip_2_0.txt
Normal file
456
doc/susp_aaip_2_0.txt
Normal file
@ -0,0 +1,456 @@
|
||||
|
||||
|
||||
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
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This text is under
|
||||
Copyright (c) 2009 - 2010 Thomas Schmitt <scdbackup@gmx.net>
|
||||
It shall only be modified in sync with libisofs and other software which
|
||||
makes use of AAIP. Please mail change requests to mailing list
|
||||
<libburn-hackers@pykix.org> or to the copyright holder in private.
|
||||
Only if you cannot reach the copyright holder for at least one month it is
|
||||
permissible to modify this text under the same license as the affected
|
||||
copy of libisofs.
|
||||
If you do so, you commit yourself to taking reasonable effort to stay in
|
||||
sync with the other interested users of this text.
|
||||
|
164
doc/susp_aaip_isofs_names.txt
Normal file
164
doc/susp_aaip_isofs_names.txt
Normal file
@ -0,0 +1,164 @@
|
||||
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.ca
|
||||
|
||||
Purpose:
|
||||
Records the range of checksummed image data (START, END), the number
|
||||
of checksum items (COUNT), the number of bytes in a single checksum item
|
||||
(SIZE), and the name of the checksum algorithm (CHECKSUM_TYPE).
|
||||
END is also the block address of the start of the checksum recording
|
||||
area in the image.
|
||||
See also isofs.cx .
|
||||
This attribute shall eventually be attached to the root directory entry
|
||||
and be global for the whole image.
|
||||
|
||||
Format of Value:
|
||||
START_LEN | START_BYTES | END_LEN | END_BYTES |
|
||||
COUNT_LEN | COUNT_BYTES | SIZE_LEN | SIZE_BYTES | CHECKSUM_TYPE
|
||||
Each number is encoded as _LEN byte and _BYTES value string.
|
||||
The _LEN fields comply to ISO 9660 Format section 7.1.1.
|
||||
The byte strings START_BYTES, END_BYTES, COUNT_BYTES, SIZE_BYTES begin
|
||||
with the most significant byte. Leading zero bytes are allowed.
|
||||
CHECKSUM_TYPE consists of the bytes after
|
||||
START_LEN + END_LEN + COUNT_LEN + SIZE_LEN + 4.
|
||||
It shall be a string of printable characters without terminating 0-byte.
|
||||
Type names shall be registered here.
|
||||
For now there is:
|
||||
"MD5" 128 bit message digest, see RFC 1321, see man md5sum
|
||||
|
||||
Example:
|
||||
LBA range 32 to 1000000 , 520 checksums recorded, MD5
|
||||
{ 1, 32,
|
||||
3, 15, 66, 64,
|
||||
2, 2, 8,
|
||||
1, 16,
|
||||
'M', 'D', '5' }
|
||||
or
|
||||
{ 4, 0, 0, 0, 32,
|
||||
4, 0, 15, 66, 64,
|
||||
4, 0, 0, 2, 8,
|
||||
1, 16,
|
||||
'M', 'D', '5' }
|
||||
|
||||
Registered:
|
||||
16 Jul 2009 by Thomas Schmitt for libisofs.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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.cx
|
||||
|
||||
Purpose:
|
||||
Records the index of the file's checksum in the checksum area at the
|
||||
end of the image. The byte address of the checksum is
|
||||
checksum_area_lba * 2048 + isofs.cx * checksum_size
|
||||
Default checksum algorithm is MD5 with a size of 16 byte.
|
||||
See also isofs.ca .
|
||||
|
||||
Format of Value:
|
||||
A byte string which begins with the most significant byte.
|
||||
|
||||
Example:
|
||||
Index 123456
|
||||
{ 1, 226, 64 }
|
||||
|
||||
Registered:
|
||||
16 Jul 2009 by Thomas Schmitt for libisofs.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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.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.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This text is under
|
||||
Copyright (c) 2009 - 2011 Thomas Schmitt <scdbackup@gmx.net>
|
||||
It shall only be modified in sync with libisofs and other software which
|
||||
makes use of AAIP. Please mail change requests to mailing list
|
||||
<libburn-hackers@pykix.org> or to the copyright holder in private.
|
||||
Only if you cannot reach the copyright holder for at least one month it is
|
||||
permissible to modify this text under the same license as the affected
|
||||
copy of libisofs.
|
||||
If you do so, you commit yourself to taking reasonable effort to stay in
|
||||
sync with the other interested users of this text.
|
||||
|
154
doc/zisofs_format.txt
Normal file
154
doc/zisofs_format.txt
Normal file
@ -0,0 +1,154 @@
|
||||
|
||||
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
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This text is under
|
||||
Copyright (c) 2009 - 2010 Thomas Schmitt <scdbackup@gmx.net>
|
||||
It shall reflect the effective technical specifications as implemented in
|
||||
zisofs-tools and the Linux kernel. So please contact mailing list
|
||||
<libburn-hackers@pykix.org> or to the copyright holder in private, if you
|
||||
want to make changes.
|
||||
Only if you cannot reach the copyright holder for at least one month it is
|
||||
permissible to modify and distribute this text under the license "BSD revised".
|
||||
|
100
libisofs/aaip-os-dummy.c
Normal file
100
libisofs/aaip-os-dummy.c
Normal file
@ -0,0 +1,100 @@
|
||||
|
||||
/*
|
||||
|
||||
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+
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
396
libisofs/aaip-os-freebsd.c
Normal file
396
libisofs/aaip-os-freebsd.c
Normal file
@ -0,0 +1,396 @@
|
||||
|
||||
/*
|
||||
|
||||
aaip-os-freebsd.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
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.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
|
||||
or filesystem does not support ACL
|
||||
-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) {
|
||||
if(errno == EOPNOTSUPP) {
|
||||
/* filesystem does not support ACL */
|
||||
if(flag & 16)
|
||||
return(2);
|
||||
|
||||
/* >>> ??? fake ACL from POSIX permissions ? */;
|
||||
|
||||
return(0);
|
||||
}
|
||||
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 */
|
||||
aaip_get_acl_text(path, &acl_text, flag & (16 | 32));
|
||||
if(acl_text == NULL)
|
||||
{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 < (ssize_t) *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 < (ssize_t) *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);
|
||||
}
|
||||
|
||||
|
526
libisofs/aaip-os-linux.c
Normal file
526
libisofs/aaip-os-linux.c
Normal file
@ -0,0 +1,526 @@
|
||||
|
||||
/*
|
||||
|
||||
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+
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.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
|
||||
or filesystem does not support ACL
|
||||
-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) {
|
||||
if(errno == ENOTSUP) {
|
||||
/* filesystem does not support ACL */
|
||||
if(flag & 16)
|
||||
return(2);
|
||||
|
||||
/* >>> ??? fake ACL from POSIX permissions ? */;
|
||||
|
||||
return(0);
|
||||
}
|
||||
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;
|
||||
char *list= NULL;
|
||||
ssize_t list_size= 0, i, num_names= 0;
|
||||
unsigned char *acl= NULL;
|
||||
char *a_acl_text= NULL, *d_acl_text= NULL;
|
||||
|
||||
#ifdef Libisofs_with_aaip_acL
|
||||
size_t acl_len= 0;
|
||||
#endif
|
||||
#ifdef Libisofs_with_aaip_xattR
|
||||
ssize_t value_ret, retry= 0;
|
||||
#endif
|
||||
|
||||
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 && (size_t) 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; (size_t) 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(list != NULL)
|
||||
free(list);
|
||||
if(ret <= 0 || (flag & (1 << 15))) {
|
||||
if(*names != NULL) {
|
||||
for(i= 0; (size_t) 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; (size_t) 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, acl_idx= 0, h_consumed;
|
||||
char *acl_text= NULL, *list= NULL;
|
||||
#ifdef Libisofs_with_aaip_xattR
|
||||
ssize_t list_size= 0;
|
||||
#endif
|
||||
|
||||
#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 < (size_t) 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);
|
||||
}
|
||||
|
||||
|
2150
libisofs/aaip_0_2.c
Normal file
2150
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,33 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*
|
||||
* 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
|
||||
* or later 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
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
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 +40,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 +55,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 +73,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 +95,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 +136,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
|
||||
@ -140,7 +150,7 @@ void iso_ring_buffer_free(IsoRingBuffer *buf)
|
||||
int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count)
|
||||
{
|
||||
size_t len;
|
||||
int bytes_write = 0;
|
||||
size_t bytes_write = 0;
|
||||
|
||||
if (buf == NULL || data == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
@ -189,14 +199,14 @@ 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
|
||||
*/
|
||||
int iso_ring_buffer_read(IsoRingBuffer *buf, uint8_t *dest, size_t count)
|
||||
{
|
||||
size_t len;
|
||||
int bytes_read = 0;
|
||||
size_t bytes_read = 0;
|
||||
|
||||
if (buf == NULL || dest == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
@ -252,7 +262,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);
|
||||
@ -283,11 +293,55 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/** Internal via buffer.h
|
||||
*
|
||||
* Get the status of a ring buffer.
|
||||
*
|
||||
* @param buf
|
||||
* The ring buffer object to inquire
|
||||
* @param size
|
||||
* Will be filled with the total size of the buffer, in bytes
|
||||
* @param free_bytes
|
||||
* Will be filled with the bytes currently available in buffer
|
||||
* @return
|
||||
* < 0 error, > 0 state:
|
||||
* 1="active" : input and consumption are active
|
||||
* 2="ending" : input has ended without error
|
||||
* 3="failing" : input had error and ended,
|
||||
* 5="abandoned" : consumption has ended prematurely
|
||||
* 6="ended" : consumption has ended without input error
|
||||
* 7="aborted" : consumption has ended after input error
|
||||
*/
|
||||
int iso_ring_buffer_get_buf_status(IsoRingBuffer *buf, size_t *size,
|
||||
size_t *free_bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (buf == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
/* get mutex */
|
||||
pthread_mutex_lock(&buf->mutex);
|
||||
if (size) {
|
||||
*size = buf->cap;
|
||||
}
|
||||
if (free_bytes) {
|
||||
*free_bytes = buf->cap - buf->size;
|
||||
}
|
||||
|
||||
ret = (buf->rend ? 4 : 0) + (buf->wend + 1);
|
||||
|
||||
pthread_mutex_unlock(&buf->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** API via libisofs.h
|
||||
*
|
||||
* 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 +356,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,18 +365,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) {
|
||||
*size = buf->cap;
|
||||
}
|
||||
if (free_bytes) {
|
||||
*free_bytes = buf->cap - buf->size;
|
||||
}
|
||||
|
||||
ret = (buf->rend ? 4 : 0) + (buf->wend + 1);
|
||||
|
||||
pthread_mutex_unlock(&buf->mutex);
|
||||
ret = iso_ring_buffer_get_buf_status(buf, size, free_bytes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2,15 +2,23 @@
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_BUFFER_H_
|
||||
#define LIBISO_BUFFER_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BLOCK_SIZE 2048
|
||||
|
||||
@ -62,6 +70,28 @@ int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count);
|
||||
*/
|
||||
int iso_ring_buffer_read(IsoRingBuffer *buf, uint8_t *dest, size_t count);
|
||||
|
||||
/** Backend of API call iso_ring_buffer_get_status()
|
||||
*
|
||||
* Get the status of a ring buffer.
|
||||
*
|
||||
* @param buf
|
||||
* The ring buffer object to inquire
|
||||
* @param size
|
||||
* Will be filled with the total size of the buffer, in bytes
|
||||
* @param free_bytes
|
||||
* Will be filled with the bytes currently available in buffer
|
||||
* @return
|
||||
* < 0 error, > 0 state:
|
||||
* 1="active" : input and consumption are active
|
||||
* 2="ending" : input has ended without error
|
||||
* 3="failing" : input had error and ended,
|
||||
* 5="abandoned" : consumption has ended prematurely
|
||||
* 6="ended" : consumption has ended without input error
|
||||
* 7="aborted" : consumption has ended after input error
|
||||
*/
|
||||
int iso_ring_buffer_get_buf_status(IsoRingBuffer *buf, size_t *size,
|
||||
size_t *free_bytes);
|
||||
|
||||
/**
|
||||
* Close the buffer (to be called by the writer).
|
||||
* You have to explicity close the buffer when you don't have more data to
|
||||
|
@ -1,18 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 - 2011 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.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
/* 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 "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
void iso_node_builder_ref(IsoNodeBuilder *builder)
|
||||
{
|
||||
@ -52,12 +67,15 @@ 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);
|
||||
if (strlen(name) > LIBISOFS_NODE_NAME_MAX)
|
||||
name[LIBISOFS_NODE_NAME_MAX] = 0;
|
||||
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,10 +101,15 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
int ret;
|
||||
struct stat info;
|
||||
IsoNode *new;
|
||||
IsoFilesystem *fs;
|
||||
char *name;
|
||||
unsigned char *aa_string = NULL;
|
||||
char *a_text = NULL, *d_text = NULL;
|
||||
char *dest = NULL;
|
||||
IsoSymlink *link;
|
||||
|
||||
if (builder == NULL || src == NULL || node == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
{ret = ISO_NULL_POINTER; goto ex;}
|
||||
}
|
||||
|
||||
/* get info about source */
|
||||
@ -96,10 +119,13 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
ret = iso_file_source_lstat(src, &info);
|
||||
}
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
name = iso_file_source_get_name(src);
|
||||
if (strlen(name) > LIBISOFS_NODE_NAME_MAX)
|
||||
name[LIBISOFS_NODE_NAME_MAX] = 0;
|
||||
fs = iso_file_source_get_filesystem(src);
|
||||
new = NULL;
|
||||
|
||||
switch (info.st_mode & S_IFMT) {
|
||||
@ -134,15 +160,20 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||
case S_IFLNK:
|
||||
{
|
||||
/* source is a symbolic link */
|
||||
char dest[PATH_MAX];
|
||||
IsoSymlink *link;
|
||||
|
||||
ret = iso_file_source_readlink(src, dest, PATH_MAX);
|
||||
LIBISO_ALLOC_MEM(dest, char, LIBISOFS_NODE_PATH_MAX);
|
||||
ret = iso_file_source_readlink(src, dest, LIBISOFS_NODE_PATH_MAX);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
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,17 +186,24 @@ 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;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
free(name);
|
||||
return ret;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* 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,13 +211,48 @@ 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 */
|
||||
if(aa_string != NULL)
|
||||
free(aa_string);
|
||||
aa_string = NULL;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
goto ex;
|
||||
} else if(aa_string != NULL) {
|
||||
free(aa_string);
|
||||
}
|
||||
|
||||
*node = new;
|
||||
return ISO_SUCCESS;
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(dest);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
void default_free(IsoNodeBuilder *builder)
|
||||
{
|
||||
/* The .free() method of IsoNodeBuilder shall free private data but not
|
||||
the builder itself. The latter is done in iso_node_builder_unref().
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_BUILDER_H_
|
||||
@ -34,8 +35,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
|
||||
|
@ -2,10 +2,15 @@
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -57,7 +62,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 +86,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 +107,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 */
|
||||
|
2014
libisofs/ecma119.c
2014
libisofs/ecma119.c
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,11 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2009 - 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_ECMA119_H_
|
||||
@ -13,16 +15,68 @@
|
||||
#include "util.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#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
|
||||
|
||||
/*
|
||||
* The maximum number of partition images that can be registered. Depending
|
||||
* on the system area type, the effectively usable number may be smaller or
|
||||
* even 0.
|
||||
*/
|
||||
#define ISO_MAX_PARTITIONS 8
|
||||
|
||||
/*
|
||||
* The cylindersize with SUN Disk Label
|
||||
* (512 bytes/sector, 640 sectors/head, 1 head/cyl = 320 KiB).
|
||||
* Expressed in ECMA-119 blocks of 2048 bytes/block.
|
||||
*/
|
||||
#define ISO_SUN_CYL_SIZE 160
|
||||
|
||||
/*
|
||||
* Maximum length of a disc label text plus 1.
|
||||
*/
|
||||
#define ISO_DISC_LABEL_SIZE 129
|
||||
|
||||
|
||||
/* The maximum lenght of an specs violating ECMA-119 file identifier.
|
||||
The theoretical limit is 254 - 34 - 28 (len of SUSP CE entry) = 192
|
||||
Currently the practical limit is 254 - 34 - 96 (non-CE RR entries) - 28 (CE)
|
||||
*/
|
||||
#ifdef Libisofs_with_rrip_rR
|
||||
#define ISO_UNTRANSLATED_NAMES_MAX 92
|
||||
#else
|
||||
#define ISO_UNTRANSLATED_NAMES_MAX 96
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Holds the options for the image generation.
|
||||
*/
|
||||
struct iso_write_opts {
|
||||
|
||||
int will_cancel;
|
||||
|
||||
int level; /**< ISO level to write at. (ECMA-119, 10) */
|
||||
|
||||
/** Which extensions to support. */
|
||||
@ -30,22 +84,34 @@ 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Convert directory names for ECMA-119 the same way as other file names
|
||||
* but do not force dots or add version numbers.
|
||||
* This violates ECMA-119 by allowing one "." and especially ISO level 1
|
||||
* by allowing DOS style 8.3 names rather than only 8 characters.
|
||||
*/
|
||||
unsigned int allow_dir_id_ext :1;
|
||||
|
||||
/**
|
||||
* Omit the version number (";1") at the end of the ISO-9660 identifiers.
|
||||
* Version numbers are usually not used.
|
||||
* bit0= ECMA-119 and Joliet (for historical reasons)
|
||||
* bit1= Joliet
|
||||
*/
|
||||
unsigned int omit_version_numbers :1;
|
||||
unsigned int omit_version_numbers :2;
|
||||
|
||||
/**
|
||||
* 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 +130,101 @@ 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
|
||||
* bit0= ECMA-119
|
||||
* bit1= Joliet
|
||||
*/
|
||||
unsigned int no_force_dots :1;
|
||||
|
||||
unsigned int no_force_dots :2;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Allow Joliet names up to 103 characters rather than 64.
|
||||
*/
|
||||
unsigned int joliet_long_names :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;
|
||||
|
||||
/**
|
||||
* Compute MD5 checksum for the whole session and record it as index 0 of
|
||||
* the checksum blocks after the data area of the session. The layout and
|
||||
* position of these blocks will be recorded in xattr "isofs.ca" of the
|
||||
* root node. See see also API call iso_image_get_session_md5().
|
||||
*/
|
||||
unsigned int md5_session_checksum :1;
|
||||
|
||||
/**
|
||||
* Compute MD5 checksums for IsoFile objects and write them to blocks
|
||||
* after the data area of the session. The layout and position of these
|
||||
* blocks will be recorded in xattr "isofs.ca" of the root node.
|
||||
* The indice of the MD5 sums will be recorded with the IsoFile directory
|
||||
* entries as xattr "isofs.cx". See also API call iso_file_get_md5().
|
||||
* bit0= compute individual checksums
|
||||
* bit1= pre-compute checksum and compare it with actual one.
|
||||
* Raise MISHAP if mismatch.
|
||||
*/
|
||||
unsigned int md5_file_checksums :2;
|
||||
|
||||
/** If files should be sorted based on their weight. */
|
||||
unsigned int sort_files :1;
|
||||
|
||||
@ -102,7 +234,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.
|
||||
@ -117,6 +249,26 @@ struct iso_write_opts {
|
||||
uid_t uid; /** uid to use when replace_uid == 2. */
|
||||
gid_t gid; /** gid to use when replace_gid == 2. */
|
||||
|
||||
/**
|
||||
* See API call iso_write_opts_set_old_empty().
|
||||
*/
|
||||
unsigned int old_empty :1;
|
||||
|
||||
/**
|
||||
* Extra Caution: This option breaks any assumptions about names that
|
||||
* are supported by ECMA-119 specifications.
|
||||
* Omit any translation which would make a file name compliant to the
|
||||
* ECMA-119 rules. This includes and exceeds omit_version_numbers,
|
||||
* max_37_char_filenames, no_force_dots bit0, allow_lowercase.
|
||||
* The maximum name length is given by this variable.
|
||||
* There is a length limit of ISO_UNTRANSLATED_NAMES_MAX characters,
|
||||
* because ECMA-119 allows 254 byte in a directory record, some
|
||||
* of them are occupied by ECMA-119, some more are needed for SUSP CE,
|
||||
* and some are fixely occupied by libisofs Rock Ridge code.
|
||||
* The default value 0 disables this feature.
|
||||
*/
|
||||
unsigned int untranslated_name_len;
|
||||
|
||||
/**
|
||||
* 0 to use IsoNode timestamps, 1 to use recording time, 2 to use
|
||||
* values from timestamp field. This has only meaning if RR extensions
|
||||
@ -133,68 +285,137 @@ 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;
|
||||
|
||||
/**
|
||||
* If not empty: A text holding parameters "name" and "timestamp" for
|
||||
* a scdbackup stream checksum tag. See scdbackup/README appendix VERIFY.
|
||||
* It makes sense only for single session images which start at LBA 0.
|
||||
* Such a tag may be part of a libisofs checksum tag block after the
|
||||
* session tag line. It then covers the whole session up to its own start
|
||||
* position.
|
||||
*/
|
||||
char scdbackup_tag_parm[100];
|
||||
|
||||
/* If not NULL: A pointer to an application provided array with
|
||||
at least 512 characters. The effectively written scdbackup tag
|
||||
will be copied to this memory location.
|
||||
*/
|
||||
char *scdbackup_tag_written;
|
||||
|
||||
/*
|
||||
* See ecma119_image : System Area related information
|
||||
*/
|
||||
char *system_area_data;
|
||||
int system_area_options;
|
||||
|
||||
/* User settable PVD time stamps */
|
||||
time_t vol_creation_time;
|
||||
time_t vol_modification_time;
|
||||
time_t vol_expiration_time;
|
||||
time_t vol_effective_time;
|
||||
/* To eventually override vol_creation_time and vol_modification_time
|
||||
* by unconverted string with timezone 0
|
||||
*/
|
||||
char vol_uuid[17];
|
||||
|
||||
/* The number of unclaimed 2K blocks before start of partition 1 as of
|
||||
the MBR in system area.
|
||||
Must be 0 or >= 16. (Actually >= number of voldescr + checksum tag)
|
||||
*/
|
||||
uint32_t partition_offset;
|
||||
/* Partition table parameter: 1 to 63, 0= disabled/default */
|
||||
int partition_secs_per_head;
|
||||
/* 1 to 255, 0= disabled/default */
|
||||
int partition_heads_per_cyl;
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
/* Parameters and state of Jigdo Template Export environment.
|
||||
*/
|
||||
struct libjte_env *libjte_handle;
|
||||
#endif /* Libisofs_with_libjtE */
|
||||
|
||||
/* A trailing padding of zero bytes which belongs to the image
|
||||
*/
|
||||
uint32_t tail_blocks;
|
||||
|
||||
/* Eventual disk file paths of prepared images which shall be appended
|
||||
after the ISO image and described by partiton table entries in a MBR
|
||||
*/
|
||||
char *appended_partitions[ISO_MAX_PARTITIONS];
|
||||
uint8_t appended_part_types[ISO_MAX_PARTITIONS];
|
||||
|
||||
/* Eventual name of the non-ISO aspect of the image. E.g. SUN ASCII label.
|
||||
*/
|
||||
char ascii_disc_label[ISO_DISC_LABEL_SIZE];
|
||||
};
|
||||
|
||||
typedef struct ecma119_image Ecma119Image;
|
||||
@ -206,9 +427,13 @@ typedef struct Iso_Image_Writer IsoImageWriter;
|
||||
|
||||
struct ecma119_image
|
||||
{
|
||||
int refcount;
|
||||
|
||||
IsoImage *image;
|
||||
Ecma119Node *root;
|
||||
|
||||
int will_cancel :1;
|
||||
|
||||
unsigned int iso_level :2;
|
||||
|
||||
/* extensions */
|
||||
@ -217,24 +442,47 @@ 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;
|
||||
|
||||
/* relaxed constraints */
|
||||
unsigned int omit_version_numbers :1;
|
||||
unsigned int allow_dir_id_ext :1;
|
||||
unsigned int omit_version_numbers :2;
|
||||
unsigned int allow_deep_paths :1;
|
||||
unsigned int allow_longer_paths :1;
|
||||
unsigned int max_37_char_filenames :1;
|
||||
unsigned int no_force_dots :1;
|
||||
unsigned int no_force_dots :2;
|
||||
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;
|
||||
|
||||
/*
|
||||
/** Allow Joliet names up to 103 characters rather than 64 */
|
||||
unsigned int joliet_long_names :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;
|
||||
|
||||
unsigned int md5_session_checksum :1;
|
||||
unsigned int md5_file_checksums :2;
|
||||
|
||||
/*
|
||||
* Mode replace. If one of these flags is set, the correspodent values are
|
||||
* replaced with values below.
|
||||
*/
|
||||
@ -250,16 +498,13 @@ struct ecma119_image
|
||||
mode_t dir_mode;
|
||||
time_t timestamp;
|
||||
|
||||
/**
|
||||
* if sort files or not. Sorting is based of the weight of each file
|
||||
*/
|
||||
int sort_files;
|
||||
unsigned int old_empty :1;
|
||||
unsigned int untranslated_name_len;
|
||||
|
||||
/**
|
||||
* In the CD, each file must have an unique inode number. So each
|
||||
* time we add a new file, this is incremented.
|
||||
* if sort files or not. Sorting is based of the weight of each file
|
||||
*/
|
||||
ino_t ino;
|
||||
int sort_files;
|
||||
|
||||
char *input_charset;
|
||||
char *output_charset;
|
||||
@ -272,8 +517,9 @@ struct ecma119_image
|
||||
off_t total_size;
|
||||
uint32_t vol_space_size;
|
||||
|
||||
/* Bytes already written, just for progress notification */
|
||||
/* Bytes already written to image output */
|
||||
off_t bytes_written;
|
||||
/* just for progress notification */
|
||||
int percent_written;
|
||||
|
||||
/*
|
||||
@ -282,7 +528,18 @@ struct ecma119_image
|
||||
*/
|
||||
uint32_t curblock;
|
||||
|
||||
/*
|
||||
/*
|
||||
* The address to be used for the content pointer of empty data files.
|
||||
*/
|
||||
uint32_t empty_file_block;
|
||||
|
||||
/*
|
||||
* The calculated block address after ECMA-119 tree and eventual
|
||||
* tree checksum tag.
|
||||
*/
|
||||
uint32_t tree_end_block;
|
||||
|
||||
/*
|
||||
* number of dirs in ECMA-119 tree, computed together with dir position,
|
||||
* and needed for path table computation in a efficient way
|
||||
*/
|
||||
@ -290,7 +547,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 +556,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,13 +565,47 @@ 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
|
||||
*/
|
||||
struct el_torito_boot_catalog *catalog;
|
||||
IsoFileSrc *cat; /**< location of the boot catalog in the new image */
|
||||
IsoFileSrc *bootimg; /**< location of the boot image in the new image */
|
||||
|
||||
int num_bootsrc;
|
||||
IsoFileSrc **bootsrc; /* location of the boot images in the new image */
|
||||
|
||||
/*
|
||||
* System Area related information
|
||||
*/
|
||||
/* Content of an embedded boot image. Valid if not NULL.
|
||||
* In that case it must point to a memory buffer at least 32 kB.
|
||||
*/
|
||||
char *system_area_data;
|
||||
/*
|
||||
* bit0= Only with DOS MBR
|
||||
* Make bytes 446 - 512 of the system area a partition
|
||||
* table which reserves partition 1 from byte 63*512 to the
|
||||
* end of the ISO image. Assumed are 63 secs/hed, 255 head/cyl.
|
||||
* (GRUB protective msdos label.)
|
||||
* This works with and without system_area_data.
|
||||
* bit1= Only with DOS MBR
|
||||
* Apply isohybrid MBR patching to the system area.
|
||||
* This works only with system_area_data plus ISOLINUX boot image
|
||||
* and only if not bit0 is set.
|
||||
* bit2-7= System area type
|
||||
* 0= DOS MBR
|
||||
* 1= MIPS Big Endian Volume Header
|
||||
* 2= DEC Boot Block for MIPS Little Endian
|
||||
* 3= SUN Disk Label for SUN SPARC
|
||||
* bit8-9= Only with DOS MBR
|
||||
* Cylinder alignment mode eventually pads the image to make it
|
||||
* end at a cylinder boundary.
|
||||
* 0 = auto (align if bit1)
|
||||
* 1 = always align to cylinder boundary
|
||||
* 2 = never align to cylinder boundary
|
||||
*/
|
||||
int system_area_options;
|
||||
|
||||
/*
|
||||
* Number of pad blocks that we need to write. Padding blocks are blocks
|
||||
@ -322,14 +613,14 @@ 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.
|
||||
*/
|
||||
uint32_t pad_blocks;
|
||||
uint32_t mspad_blocks;
|
||||
|
||||
size_t nwriters;
|
||||
IsoImageWriter **writers;
|
||||
@ -337,12 +628,94 @@ struct ecma119_image
|
||||
/* tree of files sources */
|
||||
IsoRBTree *files;
|
||||
|
||||
unsigned int checksum_idx_counter;
|
||||
void *checksum_ctx;
|
||||
off_t checksum_counter;
|
||||
uint32_t checksum_rlsb_tag_pos;
|
||||
uint32_t checksum_sb_tag_pos;
|
||||
uint32_t checksum_tree_tag_pos;
|
||||
uint32_t checksum_tag_pos;
|
||||
char image_md5[16];
|
||||
char *checksum_buffer;
|
||||
uint32_t checksum_array_pos;
|
||||
uint32_t checksum_range_start;
|
||||
uint32_t checksum_range_size;
|
||||
|
||||
char *opts_overwrite; /* Points to IsoWriteOpts->overwrite.
|
||||
Use only underneath ecma119_image_new()
|
||||
and if not NULL*/
|
||||
|
||||
/* ??? Is there a reason why we copy lots of items from IsoWriteOpts
|
||||
rather than taking ownership of the IsoWriteOpts object which
|
||||
is submitted with ecma119_image_new() ?
|
||||
*/
|
||||
|
||||
char scdbackup_tag_parm[100];
|
||||
char *scdbackup_tag_written;
|
||||
|
||||
/* Buffer for communication between burn_source and writer thread */
|
||||
IsoRingBuffer *buffer;
|
||||
|
||||
/* writer thread descriptor */
|
||||
pthread_t wthread;
|
||||
int wthread_is_running;
|
||||
pthread_attr_t th_attr;
|
||||
|
||||
/* User settable PVD time stamps */
|
||||
time_t vol_creation_time;
|
||||
time_t vol_modification_time;
|
||||
time_t vol_expiration_time;
|
||||
time_t vol_effective_time;
|
||||
/* To eventually override vol_creation_time and vol_modification_time
|
||||
* by unconverted string with timezone 0
|
||||
*/
|
||||
char vol_uuid[17];
|
||||
|
||||
/* The number of unclaimed 2K blocks before
|
||||
start of partition 1 as of the MBR in system area. */
|
||||
uint32_t partition_offset;
|
||||
/* Partition table parameter: 1 to 63, 0= disabled/default */
|
||||
int partition_secs_per_head;
|
||||
/* 1 to 255, 0= disabled/default */
|
||||
int partition_heads_per_cyl;
|
||||
|
||||
/* The currently applicable LBA offset. To be subtracted from any LBA
|
||||
* that is mentioned in volume descriptors, trees, path tables,
|
||||
* Either 0 or .partition_offset
|
||||
*/
|
||||
uint32_t eff_partition_offset;
|
||||
|
||||
/* The second ECMA-119 directory tree and path tables */
|
||||
Ecma119Node *partition_root;
|
||||
uint32_t partition_l_table_pos;
|
||||
uint32_t partition_m_table_pos;
|
||||
|
||||
/* The second Joliet directory tree and path tables */
|
||||
JolietNode *j_part_root;
|
||||
uint32_t j_part_l_path_table_pos;
|
||||
uint32_t j_part_m_path_table_pos;
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
struct libjte_env *libjte_handle;
|
||||
#endif /* Libisofs_with_libjtE */
|
||||
|
||||
uint32_t tail_blocks;
|
||||
|
||||
/* Memorized ELF parameters from MIPS Little Endian boot file */
|
||||
uint32_t mipsel_e_entry;
|
||||
uint32_t mipsel_p_offset;
|
||||
uint32_t mipsel_p_vaddr;
|
||||
uint32_t mipsel_p_filesz;
|
||||
|
||||
char *appended_partitions[ISO_MAX_PARTITIONS];
|
||||
uint8_t appended_part_types[ISO_MAX_PARTITIONS];
|
||||
/* Counted in blocks of 2048 */
|
||||
uint32_t appended_part_prepad[ISO_MAX_PARTITIONS];
|
||||
uint32_t appended_part_start[ISO_MAX_PARTITIONS];
|
||||
uint32_t appended_part_size[ISO_MAX_PARTITIONS];
|
||||
|
||||
char ascii_disc_label[ISO_DISC_LABEL_SIZE];
|
||||
|
||||
};
|
||||
|
||||
#define BP(a,b) [(b) - (a) + 1]
|
||||
@ -473,4 +846,5 @@ struct ecma119_vol_desc_terminator
|
||||
uint8_t reserved BP(8, 2048);
|
||||
};
|
||||
|
||||
|
||||
#endif /*LIBISO_ECMA119_H_*/
|
||||
|
@ -1,11 +1,20 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
/* Must be before ecma119.h because of eventual Libisofs_with_rrip_rR */
|
||||
#include "libisofs.h"
|
||||
|
||||
#include "ecma119_tree.h"
|
||||
#include "ecma119.h"
|
||||
#include "node.h"
|
||||
@ -23,7 +32,7 @@
|
||||
static
|
||||
int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
|
||||
{
|
||||
int ret, relaxed;
|
||||
int ret, relaxed, free_ascii_name= 0, force_dots = 0, max_len;
|
||||
char *ascii_name;
|
||||
char *isoname= NULL;
|
||||
|
||||
@ -32,9 +41,16 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
ret = str2ascii(img->input_charset, iso->name, &ascii_name);
|
||||
if (img->untranslated_name_len > 0) {
|
||||
ascii_name = iso->name;
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = str2ascii(img->input_charset, iso->name, &ascii_name);
|
||||
free_ascii_name = 1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
iso_msg_submit(img->image->id, ret, 0, "Can't convert %s", iso->name);
|
||||
iso_msg_submit(img->image->id, ret, 0,
|
||||
"Cannot convert name '%s' to ASCII", iso->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -43,8 +59,18 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
|
||||
} else {
|
||||
relaxed = (int)img->allow_lowercase;
|
||||
}
|
||||
if (iso->type == LIBISO_DIR) {
|
||||
if (img->max_37_char_filenames) {
|
||||
if (iso->type == LIBISO_DIR && !(img->allow_dir_id_ext)) {
|
||||
if (img->untranslated_name_len > 0) {
|
||||
if (strlen(ascii_name) > img->untranslated_name_len) {
|
||||
needs_transl:;
|
||||
iso_msg_submit(img->image->id, ISO_NAME_NEEDS_TRANSL, 0,
|
||||
"File name too long (%d > %d) for untranslated recording: '%s'",
|
||||
strlen(ascii_name), img->untranslated_name_len,
|
||||
ascii_name);
|
||||
return ISO_NAME_NEEDS_TRANSL;
|
||||
}
|
||||
isoname = strdup(ascii_name);
|
||||
} else if (img->max_37_char_filenames) {
|
||||
isoname = iso_r_dirid(ascii_name, 37, relaxed);
|
||||
} else if (img->iso_level == 1) {
|
||||
if (relaxed) {
|
||||
@ -54,37 +80,45 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
|
||||
}
|
||||
} else {
|
||||
if (relaxed) {
|
||||
isoname = iso_r_dirid(ascii_name, 8, relaxed);
|
||||
isoname = iso_r_dirid(ascii_name, 31, relaxed);
|
||||
} else {
|
||||
isoname = iso_2_dirid(ascii_name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (img->max_37_char_filenames) {
|
||||
isoname = iso_r_fileid(ascii_name, 36, relaxed,
|
||||
img->no_force_dots ? 0 : 1);
|
||||
force_dots = !((img->no_force_dots & 1) || iso->type == LIBISO_DIR);
|
||||
if (img->untranslated_name_len > 0) {
|
||||
if (strlen(ascii_name) > img->untranslated_name_len)
|
||||
goto needs_transl;
|
||||
isoname = strdup(ascii_name);
|
||||
} else if (img->max_37_char_filenames) {
|
||||
isoname = iso_r_fileid(ascii_name, 36, relaxed, force_dots);
|
||||
} else if (img->iso_level == 1) {
|
||||
if (relaxed) {
|
||||
isoname = iso_r_fileid(ascii_name, 11, relaxed,
|
||||
img->no_force_dots ? 0 : 1);
|
||||
if (relaxed || !force_dots) {
|
||||
if (strchr(ascii_name, '.') == NULL)
|
||||
max_len = 8;
|
||||
else
|
||||
max_len = 11;
|
||||
isoname = iso_r_fileid(ascii_name, max_len, relaxed,
|
||||
force_dots);
|
||||
} else {
|
||||
isoname = iso_1_fileid(ascii_name);
|
||||
}
|
||||
} else {
|
||||
if (relaxed) {
|
||||
isoname = iso_r_fileid(ascii_name, 30, relaxed,
|
||||
img->no_force_dots ? 0 : 1);
|
||||
if (relaxed || !force_dots) {
|
||||
isoname = iso_r_fileid(ascii_name, 30, relaxed, force_dots);
|
||||
} else {
|
||||
isoname = iso_2_fileid(ascii_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(ascii_name);
|
||||
if (free_ascii_name)
|
||||
free(ascii_name);
|
||||
if (isoname != NULL) {
|
||||
*name = isoname;
|
||||
return ISO_SUCCESS;
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* only possible if mem error, as check for empty names is done
|
||||
* in public tree
|
||||
*/
|
||||
@ -102,14 +136,9 @@ int create_ecma119_node(Ecma119Image *img, IsoNode *iso, Ecma119Node **node)
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* take a ref to the IsoNode */
|
||||
ecma->node = iso;
|
||||
iso_node_ref(iso);
|
||||
|
||||
/* TODO #00009 : add true support for harlinks and inode numbers */
|
||||
ecma->nlink = 1;
|
||||
ecma->ino = ++img->ino;
|
||||
|
||||
*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);
|
||||
@ -149,6 +178,30 @@ int create_dir(Ecma119Image *img, IsoDir *iso, Ecma119Node **node)
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int create_file_src(Ecma119Image *img, IsoFile *iso, IsoFileSrc **src)
|
||||
{
|
||||
int ret;
|
||||
off_t size;
|
||||
|
||||
size = iso_stream_get_size(iso->stream);
|
||||
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", ipath);
|
||||
free(ipath);
|
||||
return ret;
|
||||
}
|
||||
ret = iso_file_src_create(img, iso, src);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a regular file from a iso file
|
||||
* node.
|
||||
@ -158,25 +211,17 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node)
|
||||
{
|
||||
int ret;
|
||||
IsoFileSrc *src;
|
||||
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,
|
||||
"File \"%s\" can't be added to image because "
|
||||
"is greater than 4GB", iso->node.name);
|
||||
}
|
||||
|
||||
ret = iso_file_src_create(img, iso, &src);
|
||||
ret = create_file_src(img, iso, &src);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 +248,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;
|
||||
}
|
||||
@ -254,7 +299,7 @@ void ecma119_node_free(Ecma119Node *node)
|
||||
return;
|
||||
}
|
||||
if (node->type == ECMA119_DIR) {
|
||||
int i;
|
||||
size_t i;
|
||||
for (i = 0; i < node->info.dir->nchildren; i++) {
|
||||
ecma119_node_free(node->info.dir->children[i]);
|
||||
}
|
||||
@ -267,100 +312,141 @@ void ecma119_node_free(Ecma119Node *node)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* @param flag
|
||||
* bit0= iso is in a hidden directory. Thus hide it.
|
||||
* @return
|
||||
* 1 success, 0 node ignored, < 0 error
|
||||
*
|
||||
*
|
||||
*/
|
||||
static
|
||||
int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
int depth, int pathlen)
|
||||
int depth, int pathlen, int flag)
|
||||
{
|
||||
int ret;
|
||||
Ecma119Node *node;
|
||||
int ret, hidden;
|
||||
Ecma119Node *node = NULL;
|
||||
int max_path;
|
||||
char *iso_name= NULL;
|
||||
char *iso_name= NULL, *ipath = NULL;
|
||||
IsoFileSrc *src = NULL;
|
||||
|
||||
if (image == NULL || iso == NULL || tree == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
*tree = NULL;
|
||||
|
||||
hidden = flag & 1;
|
||||
if (iso->hidden & LIBISO_HIDE_ON_RR) {
|
||||
/* file will be ignored */
|
||||
return 0;
|
||||
hidden = 1;
|
||||
if (!((iso->hidden & LIBISO_HIDE_BUT_WRITE) ||
|
||||
iso->type == LIBISO_BOOT)) {
|
||||
return 0; /* file will be ignored */
|
||||
}
|
||||
}
|
||||
ret = get_iso_name(image, iso, &iso_name);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
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);
|
||||
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) {
|
||||
free(iso_name);
|
||||
return 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);
|
||||
|
||||
if (hidden) {
|
||||
max_path= pathlen;
|
||||
} else {
|
||||
ret = get_iso_name(image, iso, &iso_name);
|
||||
if (ret < 0) {
|
||||
iso_name = NULL; /* invalid, do not free */
|
||||
goto ex;
|
||||
}
|
||||
max_path = pathlen + 1 + (iso_name ? strlen(iso_name) : 0);
|
||||
if (!image->rockridge) {
|
||||
if ((iso->type == LIBISO_DIR && depth > 8) &&
|
||||
!image->allow_deep_paths) {
|
||||
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 directory depth "
|
||||
"is greater than 8.", ipath);
|
||||
goto ex;
|
||||
} else if (max_path > 255 && !image->allow_longer_paths) {
|
||||
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", ipath);
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (iso->type) {
|
||||
case LIBISO_FILE:
|
||||
ret = create_file(image, (IsoFile*)iso, &node);
|
||||
if (hidden) {
|
||||
ret = create_file_src(image, (IsoFile *) iso, &src);
|
||||
} else {
|
||||
ret = create_file(image, (IsoFile*)iso, &node);
|
||||
}
|
||||
break;
|
||||
case LIBISO_SYMLINK:
|
||||
if (hidden) {
|
||||
ret = 0; /* Hidden means non-existing */
|
||||
goto ex;
|
||||
}
|
||||
if (image->rockridge) {
|
||||
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 (hidden) {
|
||||
ret = 0; /* Hidden means non-existing */
|
||||
goto ex;
|
||||
}
|
||||
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:
|
||||
if (image->eltorito) {
|
||||
ret = create_boot_cat(image, (IsoBoot*)iso, &node);
|
||||
if (hidden) {
|
||||
ret = el_torito_catalog_file_src_create(image, &src);
|
||||
} else {
|
||||
ret = create_boot_cat(image, (IsoBoot*)iso, &node);
|
||||
}
|
||||
} 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:
|
||||
{
|
||||
IsoNode *pos;
|
||||
IsoDir *dir = (IsoDir*)iso;
|
||||
ret = create_dir(image, dir, &node);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
|
||||
if (!hidden) {
|
||||
ret = create_dir(image, dir, &node);
|
||||
if (ret < 0) {
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
ret = ISO_SUCCESS;
|
||||
pos = dir->children;
|
||||
while (pos) {
|
||||
int cret;
|
||||
Ecma119Node *child;
|
||||
cret = create_tree(image, pos, &child, depth + 1, max_path);
|
||||
cret = create_tree(image, pos, &child, depth + 1, max_path,
|
||||
!!hidden);
|
||||
if (cret < 0) {
|
||||
/* error */
|
||||
ecma119_node_free(node);
|
||||
ret = cret;
|
||||
break;
|
||||
} else if (cret == ISO_SUCCESS) {
|
||||
} else if (cret == ISO_SUCCESS && !hidden) {
|
||||
/* add child to this node */
|
||||
int nchildren = node->info.dir->nchildren++;
|
||||
node->info.dir->children[nchildren] = child;
|
||||
@ -372,15 +458,30 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
return ISO_ASSERT_FAILURE;
|
||||
ret = ISO_ASSERT_FAILURE;
|
||||
goto ex;
|
||||
}
|
||||
if (ret <= 0) {
|
||||
free(iso_name);
|
||||
return ret;
|
||||
goto ex;
|
||||
}
|
||||
node->iso_name = iso_name;
|
||||
*tree = node;
|
||||
return ISO_SUCCESS;
|
||||
if (!hidden) {
|
||||
node->iso_name = iso_name;
|
||||
iso_name = NULL; /* now owned by node, do not free */
|
||||
*tree = node;
|
||||
node = NULL; /* now owned by caller, do not free */
|
||||
}
|
||||
ret = ISO_SUCCESS;
|
||||
ex:
|
||||
if (iso_name != NULL)
|
||||
free(iso_name);
|
||||
if (ipath != NULL)
|
||||
free(ipath);
|
||||
if (node != NULL)
|
||||
ecma119_node_free(node);
|
||||
if (hidden && ret == ISO_SUCCESS)
|
||||
ret = 0;
|
||||
/* The sources of hidden files are now owned by the rb-tree */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -430,9 +531,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;
|
||||
@ -462,8 +563,20 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (img->untranslated_name_len) {
|
||||
/* This should not happen because no two IsoNode names should be
|
||||
identical and only unaltered IsoNode names should be seen here.
|
||||
Thus the Ema119Node names should be unique.
|
||||
*/
|
||||
iso_msg_submit(img->image->id, ISO_NAME_NEEDS_TRANSL, 0,
|
||||
"ECMA-119 file name collision: '%s'",
|
||||
children[i]->iso_name);
|
||||
ret = ISO_NAME_NEEDS_TRANSL;
|
||||
goto mangle_cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -478,10 +591,11 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
|
||||
/* compute name and extension */
|
||||
dot = strrchr(full_name, '.');
|
||||
if (dot != NULL && children[i]->type != ECMA119_DIR) {
|
||||
if (dot != NULL &&
|
||||
(children[i]->type != ECMA119_DIR || img->allow_dir_id_ext)) {
|
||||
|
||||
/*
|
||||
* File (not dir) with extension
|
||||
/*
|
||||
* File (normally 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 +605,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;
|
||||
@ -521,15 +635,15 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||
name[max] = '\0';
|
||||
}
|
||||
} else {
|
||||
/* Directory, or file without extension */
|
||||
/* Directory (normally), or file without extension */
|
||||
if (children[i]->type == ECMA119_DIR) {
|
||||
max = max_dir_len - digits;
|
||||
dot = NULL; /* dots have no meaning in dirs */
|
||||
dot = NULL; /* dots (normally) have no meaning in dirs */
|
||||
} else {
|
||||
max = max_file_len - digits;
|
||||
}
|
||||
name = full_name;
|
||||
if (max < strlen(name)) {
|
||||
if ((size_t) max < strlen(name)) {
|
||||
name[max] = '\0';
|
||||
}
|
||||
/* let ext be an empty string */
|
||||
@ -572,7 +686,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 +717,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;
|
||||
@ -639,8 +753,11 @@ static
|
||||
int mangle_tree(Ecma119Image *img, int recurse)
|
||||
{
|
||||
int max_file, max_dir;
|
||||
Ecma119Node *root;
|
||||
|
||||
if (img->max_37_char_filenames) {
|
||||
if (img->untranslated_name_len > 0) {
|
||||
max_file = max_dir = img->untranslated_name_len;
|
||||
} else if (img->max_37_char_filenames) {
|
||||
max_file = max_dir = 37;
|
||||
} else if (img->iso_level == 1) {
|
||||
max_file = 12; /* 8 + 3 + 1 */
|
||||
@ -648,17 +765,22 @@ int mangle_tree(Ecma119Image *img, int recurse)
|
||||
} else {
|
||||
max_file = max_dir = 31;
|
||||
}
|
||||
if (recurse) {
|
||||
return mangle_dir(img, img->root, max_file, max_dir);
|
||||
if (img->eff_partition_offset > 0) {
|
||||
root = img->partition_root;
|
||||
} else {
|
||||
return mangle_single_dir(img, img->root, max_file, max_dir);
|
||||
root = img->root;
|
||||
}
|
||||
if (recurse) {
|
||||
return mangle_dir(img, root, max_file, max_dir);
|
||||
} else {
|
||||
return mangle_single_dir(img, root, max_file, max_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +794,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 +830,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 +865,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 +876,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
|
||||
@ -769,18 +891,24 @@ int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen)
|
||||
{
|
||||
int ret;
|
||||
size_t max_path;
|
||||
Ecma119Node *root;
|
||||
|
||||
max_path = pathlen + 1 + max_child_name_len(dir);
|
||||
|
||||
if (level > 8 || max_path > 255) {
|
||||
ret = reparent(dir, img->root);
|
||||
if (img->eff_partition_offset > 0) {
|
||||
root = img->partition_root;
|
||||
} else {
|
||||
root = img->root;
|
||||
}
|
||||
ret = reparent(dir, root);
|
||||
if (ret < 0) {
|
||||
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,12 +927,181 @@ 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 (nodes[i]->type != ECMA119_DIR &&
|
||||
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;
|
||||
Ecma119Node *root;
|
||||
|
||||
ret = create_tree(img, (IsoNode*)img->image->root, &root, 1, 0);
|
||||
ret = create_tree(img, (IsoNode*)img->image->root, &root, 1, 0, 0);
|
||||
if (ret <= 0) {
|
||||
if (ret == 0) {
|
||||
/* unexpected error, root ignored!! This can't happen */
|
||||
@ -812,7 +1109,17 @@ int ecma119_tree_create(Ecma119Image *img)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
img->root = root;
|
||||
if (img->eff_partition_offset > 0) {
|
||||
img->partition_root = root;
|
||||
} else {
|
||||
img->root = root;
|
||||
}
|
||||
|
||||
iso_msg_debug(img->image->id, "Matching hardlinks...");
|
||||
ret = match_hardlinks(img, root, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
iso_msg_debug(img->image->id, "Sorting the low level tree...");
|
||||
sort_tree(root);
|
||||
@ -826,12 +1133,12 @@ int ecma119_tree_create(Ecma119Image *img)
|
||||
if (img->rockridge && !img->allow_deep_paths) {
|
||||
|
||||
/* reorder the tree, acording to RRIP, 4.1.5 */
|
||||
ret = reorder_tree(img, img->root, 1, 0);
|
||||
ret = reorder_tree(img, root, 1, 0);
|
||||
if (ret < 0) {
|
||||
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.
|
||||
@ -844,3 +1151,35 @@ int ecma119_tree_create(Ecma119Image *img)
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the tree for a certain IsoNode and return its owning Ecma119Node
|
||||
* or NULL.
|
||||
*/
|
||||
static
|
||||
Ecma119Node *search_iso_node(Ecma119Node *root, IsoNode *node)
|
||||
{
|
||||
size_t i;
|
||||
Ecma119Node *res = NULL;
|
||||
|
||||
if (root->node == node)
|
||||
return root;
|
||||
for (i = 0; i < root->info.dir->nchildren && res == NULL; i++) {
|
||||
if (root->info.dir->children[i]->type == ECMA119_DIR)
|
||||
res = search_iso_node(root->info.dir->children[i], node);
|
||||
else if (root->info.dir->children[i]->node == node)
|
||||
res = root->info.dir->children[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Ecma119Node *ecma119_search_iso_node(Ecma119Image *img, IsoNode *node)
|
||||
{
|
||||
Ecma119Node *res = NULL;
|
||||
|
||||
if (img->root != NULL)
|
||||
res = search_iso_node(img->root, node);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_ECMA119_TREE_H_
|
||||
@ -62,8 +63,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 */
|
||||
@ -87,4 +90,11 @@ int ecma119_tree_create(Ecma119Image *img);
|
||||
*/
|
||||
void ecma119_node_free(Ecma119Node *node);
|
||||
|
||||
/**
|
||||
* Search the tree for a certain IsoNode and return its owning Ecma119Node
|
||||
* or NULL.
|
||||
*/
|
||||
Ecma119Node *ecma119_search_iso_node(Ecma119Image *img, IsoNode *node);
|
||||
|
||||
|
||||
#endif /*LIBISO_ECMA119_TREE_H_*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,11 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2010 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -24,22 +26,55 @@
|
||||
struct Iso_Boot
|
||||
{
|
||||
IsoNode node;
|
||||
|
||||
/* Want to get content of loaded boot catalog.
|
||||
Vreixo took care not to make it an IsoFile at load time.
|
||||
So this is implemented independently of IsoStream.
|
||||
*/
|
||||
uint32_t lba;
|
||||
off_t size;
|
||||
char *content;
|
||||
};
|
||||
|
||||
/* Not more than 32 so that all entries fit into 2048 bytes */
|
||||
#define Libisofs_max_boot_imageS 32
|
||||
|
||||
struct el_torito_boot_catalog {
|
||||
IsoBoot *node; /* node of the catalog */
|
||||
struct el_torito_boot_image *image; /* default boot image */
|
||||
|
||||
int num_bootimages;
|
||||
struct el_torito_boot_image *bootimages[Libisofs_max_boot_imageS];
|
||||
/* [0]= default boot image */
|
||||
|
||||
/* Weight value for image sorting */
|
||||
int sort_weight;
|
||||
};
|
||||
|
||||
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 */
|
||||
/**
|
||||
* Whether the boot image seems to contain a boot_info_table
|
||||
*/
|
||||
unsigned int seems_boot_info_table:1;
|
||||
/**
|
||||
* isolinux options
|
||||
* bit 0 -> whether to patch image
|
||||
* bit 1 -> whether to put built-in isolinux 3.72 isohybrid-MBR into image
|
||||
* System Area (deprecated)
|
||||
*/
|
||||
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. */
|
||||
short load_size; /**< Number of sectors to load. */
|
||||
|
||||
/* Byte 1 of Validation Entry or Section Header Entry:
|
||||
0= 80x86, 1= PowerPC, 2= Mac, 0xef= EFI */
|
||||
uint8_t platform_id;
|
||||
uint8_t id_string[28];
|
||||
uint8_t selection_crit[20];
|
||||
};
|
||||
|
||||
/** El-Torito, 2.1 */
|
||||
@ -69,8 +104,8 @@ struct el_torito_default_entry {
|
||||
struct el_torito_section_header {
|
||||
uint8_t header_indicator BP(1, 1);
|
||||
uint8_t platform_id BP(2, 2);
|
||||
uint8_t number BP(3, 4);
|
||||
uint8_t character BP(5, 32);
|
||||
uint8_t num_entries BP(3, 4);
|
||||
uint8_t id_string BP(5, 32);
|
||||
};
|
||||
|
||||
/** El-Torito, 2.4 */
|
||||
@ -100,4 +135,14 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src);
|
||||
*/
|
||||
int eltorito_writer_create(Ecma119Image *target);
|
||||
|
||||
/**
|
||||
* Insert boot info table content into buf.
|
||||
*
|
||||
* @return
|
||||
* 1 on success, 0 error (but continue), < 0 error
|
||||
*/
|
||||
int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba,
|
||||
uint32_t boot_lba, uint32_t imgsize);
|
||||
|
||||
|
||||
#endif /* LIBISO_ELTORITO_H */
|
||||
|
@ -1,49 +1,67 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* 2010 - 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "filesrc.h"
|
||||
#include "node.h"
|
||||
#include "util.h"
|
||||
#include "writer.h"
|
||||
#include "messages.h"
|
||||
#include "image.h"
|
||||
#include "stream.h"
|
||||
#include "md5.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#ifdef Xorriso_standalonE
|
||||
|
||||
#ifdef Xorriso_with_libjtE
|
||||
#include "../libjte/libjte.h"
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
#include <libjte/libjte.h>
|
||||
#endif
|
||||
|
||||
#endif /* ! Xorriso_standalonE */
|
||||
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX Libisofs_default_path_maX
|
||||
#endif
|
||||
|
||||
|
||||
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)
|
||||
@ -53,6 +71,8 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||
unsigned int fs_id;
|
||||
dev_t dev_id;
|
||||
ino_t ino_id;
|
||||
int cret, no_md5= 0;
|
||||
void *xipt = NULL;
|
||||
|
||||
if (img == NULL || file == NULL || src == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
@ -60,35 +80,93 @@ 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) {
|
||||
if (ret == 0 && (*src)->checksum_index > 0) {
|
||||
/* Duplicate file source was mapped to previously registered source
|
||||
*/
|
||||
cret = iso_file_set_isofscx(file, (*src)->checksum_index, 0);
|
||||
if (cret < 0)
|
||||
ret = cret;
|
||||
}
|
||||
free(fsrc->sections);
|
||||
free(fsrc);
|
||||
return ret;
|
||||
}
|
||||
iso_stream_ref(fsrc->stream);
|
||||
|
||||
if ((img->md5_file_checksums & 1) &&
|
||||
file->from_old_session && img->appendable) {
|
||||
ret = iso_node_get_xinfo((IsoNode *) file, checksum_md5_xinfo_func,
|
||||
&xipt);
|
||||
if (ret <= 0)
|
||||
ret = iso_node_get_xinfo((IsoNode *) file, checksum_cx_xinfo_func,
|
||||
&xipt);
|
||||
if (ret <= 0)
|
||||
/* Omit MD5 indexing with old image nodes which have no MD5 */
|
||||
no_md5 = 1;
|
||||
}
|
||||
|
||||
if ((img->md5_file_checksums & 1) && !no_md5) {
|
||||
img->checksum_idx_counter++;
|
||||
if (img->checksum_idx_counter < 0x7fffffff) {
|
||||
fsrc->checksum_index = img->checksum_idx_counter;
|
||||
} else {
|
||||
fsrc->checksum_index= 0;
|
||||
img->checksum_idx_counter= 0x7fffffff; /* keep from rolling over */
|
||||
}
|
||||
cret = iso_file_set_isofscx(file, (*src)->checksum_index, 0);
|
||||
if (cret < 0)
|
||||
return cret;
|
||||
}
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +174,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 +185,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 +194,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);
|
||||
}
|
||||
|
||||
@ -153,13 +232,19 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
|
||||
t = writer->target;
|
||||
|
||||
/* Normally reserve a single zeroed block for all files which have
|
||||
no block address: symbolic links, device files, empty data files.
|
||||
*/
|
||||
if (! t->old_empty)
|
||||
t->curblock++;
|
||||
|
||||
/* on appendable images, ms files shouldn't be included */
|
||||
if (t->appendable) {
|
||||
inc_item = is_ms_file;
|
||||
} 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 +258,28 @@ 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
|
||||
*/
|
||||
if (section_size <= 0) {
|
||||
file->sections[extent].block = t->empty_file_block;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -210,102 +315,137 @@ int filesrc_close(IsoFileSrc *file)
|
||||
static
|
||||
int filesrc_read(IsoFileSrc *file, char *buf, size_t count)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
size_t got;
|
||||
|
||||
/* loop to ensure the full buffer is filled */
|
||||
do {
|
||||
ssize_t result;
|
||||
result = iso_stream_read(file->stream, buf + bytes, count - bytes);
|
||||
if (result < 0) {
|
||||
/* fill buffer with 0s and return */
|
||||
memset(buf + bytes, 0, count - bytes);
|
||||
return result;
|
||||
}
|
||||
if (result == 0)
|
||||
break;
|
||||
bytes += result;
|
||||
} while (bytes < count);
|
||||
return iso_stream_read_buffer(file->stream, buf, count, &got);
|
||||
}
|
||||
|
||||
if (bytes < count) {
|
||||
/* eof */
|
||||
memset(buf + bytes, 0, count - bytes);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
/* @return 1=ok, md5 is valid,
|
||||
0= not ok, go on,
|
||||
<0 fatal error, abort
|
||||
*/
|
||||
static
|
||||
int filesrc_make_md5(Ecma119Image *t, IsoFileSrc *file, char md5[16], int flag)
|
||||
{
|
||||
return iso_stream_make_md5(file->stream, md5, 0);
|
||||
}
|
||||
|
||||
static
|
||||
int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
{
|
||||
int res;
|
||||
int res, ret, was_error;
|
||||
size_t i, b;
|
||||
Ecma119Image *t;
|
||||
Ecma119Image *t = NULL;
|
||||
IsoFileSrc *file;
|
||||
IsoFileSrc **filelist;
|
||||
char *name;
|
||||
char buffer[BLOCK_SIZE];
|
||||
char *name = NULL;
|
||||
char *buffer = NULL;
|
||||
off_t file_size;
|
||||
uint32_t nblocks;
|
||||
void *ctx= NULL;
|
||||
char md5[16], pre_md5[16];
|
||||
int pre_md5_valid = 0;
|
||||
#ifdef Libisofs_with_libjtE
|
||||
int jte_begun = 0;
|
||||
#endif
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
ret = ISO_ASSERT_FAILURE; goto ex;
|
||||
}
|
||||
|
||||
LIBISO_ALLOC_MEM(name, char, PATH_MAX);
|
||||
LIBISO_ALLOC_MEM(buffer, char, BLOCK_SIZE);
|
||||
t = writer->target;
|
||||
filelist = writer->data;
|
||||
|
||||
iso_msg_debug(t->image->id, "Writing Files...");
|
||||
|
||||
/* Normally write a single zeroed block as block address target for all
|
||||
files which have no block address:
|
||||
symbolic links, device files, empty data files.
|
||||
*/
|
||||
if (! t->old_empty) {
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
was_error = 0;
|
||||
file_size = iso_file_src_get_size(file);
|
||||
nblocks = DIV_UP(file_size, BLOCK_SIZE);
|
||||
pre_md5_valid = 0;
|
||||
if (file->checksum_index > 0 && (t->md5_file_checksums & 2)) {
|
||||
/* Obtain an MD5 of content by a first read pass */
|
||||
pre_md5_valid = filesrc_make_md5(t, file, pre_md5, 0);
|
||||
}
|
||||
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);
|
||||
was_error = 1;
|
||||
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 */
|
||||
ret = res; /* aborted due to error severity */
|
||||
goto ex;
|
||||
}
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
for (b = 0; b < nblocks; ++b) {
|
||||
res = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (res < 0) {
|
||||
/* ko, writer error, we need to go out! */
|
||||
return res;
|
||||
ret = res;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
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);
|
||||
was_error = 1;
|
||||
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 */
|
||||
ret = res; /* aborted due to error severity */
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
#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
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
if (t->libjte_handle != NULL) {
|
||||
res = libjte_begin_data_file(t->libjte_handle, name,
|
||||
BLOCK_SIZE, file_size);
|
||||
if (res <= 0) {
|
||||
res = iso_libjte_forward_msgs(t->libjte_handle, t->image->id,
|
||||
ISO_LIBJTE_FILE_FAILED, 0);
|
||||
if (res < 0) {
|
||||
filesrc_close(file);
|
||||
ret = ISO_LIBJTE_FILE_FAILED;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
jte_begun = 1;
|
||||
}
|
||||
#endif /* Libisofs_with_libjtE */
|
||||
|
||||
if (file->checksum_index > 0) {
|
||||
/* initialize file checksum */
|
||||
res = iso_md5_start(&ctx);
|
||||
if (res <= 0)
|
||||
file->checksum_index = 0;
|
||||
}
|
||||
/* write file contents to image */
|
||||
for (b = 0; b < nblocks; ++b) {
|
||||
int wres;
|
||||
@ -318,7 +458,18 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
if (wres < 0) {
|
||||
/* ko, writer error, we need to go out! */
|
||||
filesrc_close(file);
|
||||
return wres;
|
||||
ret = wres;
|
||||
goto ex;
|
||||
}
|
||||
if (file->checksum_index > 0) {
|
||||
/* Add to file checksum */
|
||||
if (file_size - b * BLOCK_SIZE > BLOCK_SIZE)
|
||||
res = BLOCK_SIZE;
|
||||
else
|
||||
res = file_size - b * BLOCK_SIZE;
|
||||
res = iso_md5_compute(ctx, buffer, res);
|
||||
if (res <= 0)
|
||||
file->checksum_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,7 +477,8 @@ 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);
|
||||
was_error = 1;
|
||||
if (res < 0) {
|
||||
/* error */
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||
@ -336,12 +488,12 @@ 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 */
|
||||
ret = res; /* aborted due error severity */
|
||||
goto ex;
|
||||
}
|
||||
|
||||
|
||||
/* fill with 0s */
|
||||
iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
"Filling with 0");
|
||||
@ -350,13 +502,77 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||
res = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (res < 0) {
|
||||
/* ko, writer error, we need to go out! */
|
||||
return res;
|
||||
ret = res;
|
||||
goto ex;
|
||||
}
|
||||
if (file->checksum_index > 0) {
|
||||
/* Add to file checksum */
|
||||
if (file_size - b * BLOCK_SIZE > BLOCK_SIZE)
|
||||
res = BLOCK_SIZE;
|
||||
else
|
||||
res = file_size - b * BLOCK_SIZE;
|
||||
res = iso_md5_compute(ctx, buffer, res);
|
||||
if (res <= 0)
|
||||
file->checksum_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (file->checksum_index > 0 &&
|
||||
file->checksum_index <= t->checksum_idx_counter) {
|
||||
/* Obtain checksum and dispose checksum context */
|
||||
res = iso_md5_end(&ctx, md5);
|
||||
if (res <= 0)
|
||||
file->checksum_index = 0;
|
||||
if ((t->md5_file_checksums & 2) && pre_md5_valid > 0 &&
|
||||
!was_error) {
|
||||
if (! iso_md5_match(md5, pre_md5)) {
|
||||
/* Issue MISHAP event */
|
||||
iso_report_errfile(name, ISO_MD5_STREAM_CHANGE, 0, 0);
|
||||
was_error = 1;
|
||||
res = iso_msg_submit(t->image->id, ISO_MD5_STREAM_CHANGE,0,
|
||||
"Content of file '%s' changed while it was written into the image.",
|
||||
name);
|
||||
if (res < 0) {
|
||||
ret = res; /* aborted due to error severity */
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Write md5 into checksum buffer at file->checksum_index */
|
||||
memcpy(t->checksum_buffer + 16 * file->checksum_index, md5, 16);
|
||||
}
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
if (t->libjte_handle != NULL) {
|
||||
res = libjte_end_data_file(t->libjte_handle);
|
||||
if (res <= 0) {
|
||||
iso_libjte_forward_msgs(t->libjte_handle, t->image->id,
|
||||
ISO_LIBJTE_FILE_FAILED, 0);
|
||||
ret = ISO_LIBJTE_FILE_FAILED;
|
||||
goto ex;
|
||||
}
|
||||
jte_begun = 0;
|
||||
}
|
||||
#endif /* Libisofs_with_libjtE */
|
||||
|
||||
}
|
||||
|
||||
return ISO_SUCCESS;
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (ctx != NULL) /* avoid any memory leak */
|
||||
iso_md5_end(&ctx, md5);
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
if (jte_begun && t != NULL) {
|
||||
libjte_end_data_file(t->libjte_handle);
|
||||
iso_libjte_forward_msgs(t->libjte_handle, t->image->id,
|
||||
ISO_LIBJTE_END_FAILED, 0);
|
||||
}
|
||||
#endif /* Libisofs_with_libjtE */
|
||||
|
||||
LIBISO_FREE_MEM(buffer);
|
||||
LIBISO_FREE_MEM(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
@ -371,9 +587,9 @@ int iso_file_src_writer_create(Ecma119Image *target)
|
||||
{
|
||||
IsoImageWriter *writer;
|
||||
|
||||
writer = malloc(sizeof(IsoImageWriter));
|
||||
writer = calloc(1, sizeof(IsoImageWriter));
|
||||
if (writer == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
writer->compute_data_blocks = filesrc_writer_compute_data_blocks;
|
||||
|
@ -1,9 +1,10 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*
|
||||
* 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_FILESRC_H_
|
||||
#define LIBISO_FILESRC_H_
|
||||
@ -12,12 +13,23 @@
|
||||
#include "stream.h"
|
||||
#include "ecma119.h"
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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 */
|
||||
unsigned int checksum_index :31;
|
||||
|
||||
/** File Sections of the file in the image */
|
||||
struct iso_file_section *sections;
|
||||
int nsections;
|
||||
|
||||
int sort_weight;
|
||||
IsoStream *stream;
|
||||
};
|
||||
@ -26,12 +38,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
|
||||
@ -39,18 +51,18 @@ int iso_file_src_cmp(const void *n1, const void *n2);
|
||||
* @param src
|
||||
* Will be filled with a pointer to the IsoFileSrc
|
||||
* @return
|
||||
* 1 on success, < 0 on error
|
||||
* 1 if new object was created, 0 if object existed, < 0 on error
|
||||
*/
|
||||
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 +70,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 +88,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);
|
||||
|
71
libisofs/filter.c
Normal file
71
libisofs/filter.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
|
76
libisofs/filter.h
Normal file
76
libisofs/filter.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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
|
||||
* or later 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_*/
|
817
libisofs/filters/external.c
Normal file
817
libisofs/filters/external.c
Normal file
@ -0,0 +1,817 @@
|
||||
/*
|
||||
* Copyright (c) 2009 - 2011 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
|
||||
* or later 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "../libisofs.h"
|
||||
#include "../filter.h"
|
||||
#include "../fsource.h"
|
||||
#include "../stream.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.
|
||||
*/
|
||||
|
||||
/* IMPORTANT: Any change must be reflected by extf_clone_stream() */
|
||||
/*
|
||||
* 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_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
|
||||
{
|
||||
int ret;
|
||||
IsoStream *new_input_stream, *stream;
|
||||
ExternalFilterStreamData *stream_data, *old_stream_data;
|
||||
|
||||
if (flag)
|
||||
return ISO_STREAM_NO_CLONE; /* unknown option required */
|
||||
|
||||
stream_data = calloc(1, sizeof(ExternalFilterStreamData));
|
||||
if (stream_data == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
ret = iso_stream_clone_filter_common(old_stream, &stream,
|
||||
&new_input_stream, 0);
|
||||
if (ret < 0) {
|
||||
free((char *) stream_data);
|
||||
return ret;
|
||||
}
|
||||
old_stream_data = (ExternalFilterStreamData *) old_stream->data;
|
||||
stream_data->id = ++extf_ino_id;
|
||||
stream_data->orig = new_input_stream;
|
||||
stream_data->cmd = old_stream_data->cmd;
|
||||
stream_data->cmd->refcount++;
|
||||
stream_data->size = old_stream_data->size;
|
||||
stream_data->running = NULL;
|
||||
stream->data = stream_data;
|
||||
*new_stream = stream;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
int extf_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
/* Function is defined after definition of extf_stream_class */
|
||||
|
||||
|
||||
IsoStreamIface extf_stream_class = {
|
||||
4,
|
||||
"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,
|
||||
extf_clone_stream
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
802
libisofs/filters/gzip.c
Normal file
802
libisofs/filters/gzip.c
Normal file
@ -0,0 +1,802 @@
|
||||
/*
|
||||
* Copyright (c) 2009 - 2011 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
|
||||
* or later 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)."
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "../libisofs.h"
|
||||
#include "../filter.h"
|
||||
#include "../fsource.h"
|
||||
#include "../util.h"
|
||||
#include "../stream.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;
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
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;
|
||||
}
|
||||
memset(&(o->strm), 0, sizeof(o->strm));
|
||||
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;
|
||||
o->do_flush = Z_NO_FLUSH;
|
||||
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;
|
||||
}
|
||||
#endif /* Libisofs_with_zliB */
|
||||
|
||||
|
||||
/* ---------------------------- 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
|
||||
*/
|
||||
/* IMPORTANT: Any change must be reflected by gzip_clone_stream() */
|
||||
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;
|
||||
|
||||
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
/* Each individual GzipFilterStreamData needs a unique id number. */
|
||||
/* >>> This is very suboptimal:
|
||||
The counter can rollover.
|
||||
*/
|
||||
static ino_t gzip_ino_id = 0;
|
||||
|
||||
#endif /* Libisofs_with_zliB */
|
||||
|
||||
|
||||
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 ((int) 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_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
int ret;
|
||||
IsoStream *new_input_stream, *stream;
|
||||
GzipFilterStreamData *stream_data, *old_stream_data;
|
||||
|
||||
if (flag)
|
||||
return ISO_STREAM_NO_CLONE; /* unknown option required */
|
||||
|
||||
stream_data = calloc(1, sizeof(GzipFilterStreamData));
|
||||
if (stream_data == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
ret = iso_stream_clone_filter_common(old_stream, &stream,
|
||||
&new_input_stream, 0);
|
||||
if (ret < 0) {
|
||||
free((char *) stream_data);
|
||||
return ret;
|
||||
}
|
||||
old_stream_data = (GzipFilterStreamData *) old_stream->data;
|
||||
stream_data->orig = new_input_stream;
|
||||
stream_data->size = old_stream_data->size;
|
||||
stream_data->running = NULL;
|
||||
stream_data->id = ++gzip_ino_id;
|
||||
stream->data = stream_data;
|
||||
*new_stream = stream;
|
||||
return ISO_SUCCESS;
|
||||
|
||||
#else /* Libisofs_with_zliB */
|
||||
|
||||
return ISO_STREAM_NO_CLONE;
|
||||
|
||||
#endif /* ! Libisofs_with_zliB */
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
|
||||
|
||||
IsoStreamIface gzip_stream_compress_class = {
|
||||
4,
|
||||
"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,
|
||||
gzip_clone_stream
|
||||
};
|
||||
|
||||
|
||||
IsoStreamIface gzip_stream_uncompress_class = {
|
||||
4,
|
||||
"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,
|
||||
gzip_clone_stream
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#ifdef Libisofs_with_zliB
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* Libisofs_with_zliB */
|
||||
|
||||
/*
|
||||
* @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;
|
||||
}
|
||||
|
1215
libisofs/filters/zisofs.c
Normal file
1215
libisofs/filters/zisofs.c
Normal file
File diff suppressed because it is too large
Load Diff
766
libisofs/find.c
Normal file
766
libisofs/find.c
Normal file
@ -0,0 +1,766 @@
|
||||
/*
|
||||
* 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
|
2374
libisofs/fs_image.c
2374
libisofs/fs_image.c
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 - 2011 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.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Filesystem/FileSource implementation to access the local filesystem.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "fsource.h"
|
||||
#include "util.h"
|
||||
#include "aaip_0_2.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
@ -32,6 +39,7 @@ int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
|
||||
*/
|
||||
IsoFilesystem *lfs= NULL;
|
||||
|
||||
/* IMPORTANT: Any change must be reflected by lfs_clone_src() */
|
||||
typedef struct
|
||||
{
|
||||
/** reference to the parent (if root it points to itself) */
|
||||
@ -54,9 +62,19 @@ char* lfs_get_path(IsoFileSource *src)
|
||||
if (data->parent == src) {
|
||||
return strdup("/");
|
||||
} else {
|
||||
char *path = lfs_get_path(data->parent);
|
||||
int pathlen = strlen(path);
|
||||
path = realloc(path, pathlen + strlen(data->name) + 2);
|
||||
char *path, *new_path;
|
||||
int pathlen;
|
||||
|
||||
path = lfs_get_path(data->parent);
|
||||
if (path == NULL)
|
||||
return NULL;
|
||||
pathlen = strlen(path);
|
||||
new_path = realloc(path, pathlen + strlen(data->name) + 2);
|
||||
if (new_path == NULL) {
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
path= new_path;
|
||||
if (pathlen != 1) {
|
||||
/* pathlen can only be 1 for root */
|
||||
path[pathlen] = '/';
|
||||
@ -77,14 +95,14 @@ char* lfs_get_name(IsoFileSource *src)
|
||||
static
|
||||
int lfs_lstat(IsoFileSource *src, struct stat *info)
|
||||
{
|
||||
_LocalFsFileSource *data;
|
||||
char *path;
|
||||
|
||||
if (src == NULL || info == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = src->data;
|
||||
path = lfs_get_path(src);
|
||||
if (path == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
|
||||
if (lstat(path, info) != 0) {
|
||||
int err;
|
||||
@ -110,6 +128,7 @@ int lfs_lstat(IsoFileSource *src, struct stat *info)
|
||||
err = ISO_FILE_ERROR;
|
||||
break;
|
||||
}
|
||||
free(path);
|
||||
return err;
|
||||
}
|
||||
free(path);
|
||||
@ -119,14 +138,14 @@ int lfs_lstat(IsoFileSource *src, struct stat *info)
|
||||
static
|
||||
int lfs_stat(IsoFileSource *src, struct stat *info)
|
||||
{
|
||||
_LocalFsFileSource *data;
|
||||
char *path;
|
||||
|
||||
if (src == NULL || info == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = src->data;
|
||||
path = lfs_get_path(src);
|
||||
if (path == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
|
||||
if (stat(path, info) != 0) {
|
||||
int err;
|
||||
@ -152,6 +171,7 @@ int lfs_stat(IsoFileSource *src, struct stat *info)
|
||||
err = ISO_FILE_ERROR;
|
||||
break;
|
||||
}
|
||||
free(path);
|
||||
return err;
|
||||
}
|
||||
free(path);
|
||||
@ -162,13 +182,11 @@ static
|
||||
int lfs_access(IsoFileSource *src)
|
||||
{
|
||||
int ret;
|
||||
_LocalFsFileSource *data;
|
||||
char *path;
|
||||
|
||||
if (src == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
data = src->data;
|
||||
path = lfs_get_path(src);
|
||||
|
||||
ret = iso_eaccess(path);
|
||||
@ -190,7 +208,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 +269,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 +318,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,15 +405,14 @@ int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return ISO_FILE_NOT_OPENNED;
|
||||
return ISO_FILE_NOT_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int lfs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
||||
{
|
||||
int size;
|
||||
_LocalFsFileSource *data;
|
||||
int size, ret;
|
||||
char *path;
|
||||
|
||||
if (src == NULL || buf == NULL) {
|
||||
@ -360,14 +423,13 @@ int lfs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
||||
return ISO_WRONG_ARG_VALUE;
|
||||
}
|
||||
|
||||
data = src->data;
|
||||
path = lfs_get_path(src);
|
||||
|
||||
/*
|
||||
* invoke readlink, with bufsiz -1 to reserve an space for
|
||||
* the NULL character
|
||||
*/
|
||||
size = readlink(path, buf, bufsiz - 1);
|
||||
size = readlink(path, buf, bufsiz);
|
||||
free(path);
|
||||
if (size < 0) {
|
||||
/* error */
|
||||
@ -391,8 +453,13 @@ int lfs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
||||
}
|
||||
|
||||
/* NULL-terminate the buf */
|
||||
ret = ISO_SUCCESS;
|
||||
if ((size_t) size >= bufsiz) {
|
||||
ret = ISO_RR_PATH_TOO_LONG;
|
||||
size = bufsiz - 1;
|
||||
}
|
||||
buf[size] = '\0';
|
||||
return ISO_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
@ -420,8 +487,107 @@ 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;
|
||||
|
||||
*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);
|
||||
if (path == NULL) {
|
||||
ret = ISO_NULL_POINTER;
|
||||
goto ex;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static
|
||||
int lfs_clone_src(IsoFileSource *old_source,
|
||||
IsoFileSource **new_source, int flag)
|
||||
{
|
||||
IsoFileSource *src = NULL;
|
||||
char *new_name = NULL;
|
||||
_LocalFsFileSource *old_data, *new_data = NULL;
|
||||
|
||||
if (flag)
|
||||
return ISO_STREAM_NO_CLONE; /* unknown option required */
|
||||
|
||||
old_data = (_LocalFsFileSource *) old_source->data;
|
||||
*new_source = NULL;
|
||||
src = calloc(1, sizeof(IsoFileSource));
|
||||
if (src == NULL)
|
||||
goto no_mem;
|
||||
new_name = strdup(old_data->name);
|
||||
if (new_name == NULL)
|
||||
goto no_mem;
|
||||
|
||||
new_data = calloc(1, sizeof(_LocalFsFileSource));
|
||||
if (new_data == NULL)
|
||||
goto no_mem;
|
||||
new_data->openned = 0;
|
||||
new_data->info.fd = -1; /* the value does not matter with (openned == 0) */
|
||||
new_data->name = new_name;
|
||||
new_data->parent = old_data->parent;
|
||||
|
||||
src->class = old_source->class;
|
||||
src->refcount = 1;
|
||||
src->data = new_data;
|
||||
*new_source = src;
|
||||
|
||||
iso_file_source_ref(new_data->parent);
|
||||
iso_filesystem_ref(lfs);
|
||||
return ISO_SUCCESS;
|
||||
no_mem:;
|
||||
if (src != NULL)
|
||||
free((char *) src);
|
||||
if (new_data != NULL)
|
||||
free((char *) new_data);
|
||||
if (new_name != NULL)
|
||||
free(new_name);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
|
||||
IsoFileSourceIface lfs_class = {
|
||||
0, /* version */
|
||||
|
||||
2, /* version */
|
||||
lfs_get_path,
|
||||
lfs_get_name,
|
||||
lfs_lstat,
|
||||
@ -433,9 +599,14 @@ IsoFileSourceIface lfs_class = {
|
||||
lfs_readdir,
|
||||
lfs_readlink,
|
||||
lfs_get_filesystem,
|
||||
lfs_free
|
||||
lfs_free,
|
||||
lfs_lseek,
|
||||
lfs_get_aa_string,
|
||||
lfs_clone_src
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
@ -643,3 +814,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;
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,15 @@
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "fsource.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -92,6 +97,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 +120,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,9 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2009 - 2011 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.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_FSOURCE_H_
|
||||
@ -20,6 +22,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 +32,17 @@
|
||||
*/
|
||||
int iso_local_filesystem_new(IsoFilesystem **fs);
|
||||
|
||||
|
||||
/* Rank two IsoFileSource of ifs_class 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);
|
||||
|
||||
|
||||
/* Create an independent copy of an ifs_class IsoFileSource.
|
||||
*/
|
||||
int iso_ifs_source_clone(IsoFileSource *old_source, IsoFileSource **new_source,
|
||||
int flag);
|
||||
|
||||
|
||||
#endif /*LIBISO_FSOURCE_H_*/
|
||||
|
412
libisofs/image.c
412
libisofs/image.c
@ -1,11 +1,17 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "image.h"
|
||||
#include "node.h"
|
||||
@ -14,22 +20,23 @@
|
||||
|
||||
#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
|
||||
* Location where the image pointer will be stored.
|
||||
* @return
|
||||
* 1 sucess, < 0 error
|
||||
* 1 success, < 0 error
|
||||
*/
|
||||
int iso_image_new(const char *name, IsoImage **image)
|
||||
{
|
||||
int res;
|
||||
int res, i;
|
||||
IsoImage *img;
|
||||
|
||||
if (image == NULL) {
|
||||
@ -71,6 +78,21 @@ int iso_image_new(const char *name, IsoImage **image)
|
||||
img->volset_id = strdup(name);
|
||||
img->volume_id = strdup(name);
|
||||
}
|
||||
img->system_area_data = NULL;
|
||||
img->system_area_options = 0;
|
||||
img->num_mips_boot_files = 0;
|
||||
for (i = 0; i < 15; i++)
|
||||
img->mips_boot_file_paths[i] = NULL;
|
||||
img->builder_ignore_acl = 1;
|
||||
img->builder_ignore_ea = 1;
|
||||
img->inode_counter = 0;
|
||||
img->used_inodes = NULL;
|
||||
img->used_inodes_start = 0;
|
||||
img->checksum_start_lba = 0;
|
||||
img->checksum_end_lba = 0;
|
||||
img->checksum_idx_count = 0;
|
||||
img->checksum_array = NULL;
|
||||
img->generator_is_running = 0;
|
||||
*image = img;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
@ -84,8 +106,8 @@ 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
|
||||
* Decrements the reference counting of the given image.
|
||||
* 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)
|
||||
@ -108,6 +130,7 @@ void iso_image_unref(IsoImage *image)
|
||||
iso_node_builder_unref(image->builder);
|
||||
iso_filesystem_unref(image->fs);
|
||||
el_torito_boot_catalog_free(image->bootcat);
|
||||
iso_image_give_up_mips_boot(image, 0);
|
||||
free(image->volset_id);
|
||||
free(image->volume_id);
|
||||
free(image->publisher_id);
|
||||
@ -117,15 +140,33 @@ 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);
|
||||
if (image->system_area_data != NULL)
|
||||
free(image->system_area_data);
|
||||
iso_image_free_checksums(image, 0);
|
||||
free(image);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int iso_image_free_checksums(IsoImage *image, int flag)
|
||||
{
|
||||
image->checksum_start_lba = 0;
|
||||
image->checksum_end_lba = 0;
|
||||
image->checksum_idx_count = 0;
|
||||
if (image->checksum_array != NULL)
|
||||
free(image->checksum_array);
|
||||
image->checksum_array = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -136,19 +177,19 @@ void iso_image_unref(IsoImage *image)
|
||||
*/
|
||||
int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
|
||||
{
|
||||
if (image == NULL || (data != NULL && free == NULL)) {
|
||||
if (image == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
|
||||
if (image->user_data != NULL) {
|
||||
/* free previously attached data */
|
||||
if (image->user_data_free) {
|
||||
if (image->user_data_free != NULL) {
|
||||
image->user_data_free(image->user_data);
|
||||
}
|
||||
image->user_data = NULL;
|
||||
image->user_data_free = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (data != NULL) {
|
||||
image->user_data = data;
|
||||
image->user_data_free = give_up;
|
||||
@ -177,6 +218,8 @@ void iso_image_set_volset_id(IsoImage *image, const char *volset_id)
|
||||
|
||||
const char *iso_image_get_volset_id(const IsoImage *image)
|
||||
{
|
||||
if (image->volset_id == NULL)
|
||||
return "";
|
||||
return image->volset_id;
|
||||
}
|
||||
|
||||
@ -188,6 +231,8 @@ void iso_image_set_volume_id(IsoImage *image, const char *volume_id)
|
||||
|
||||
const char *iso_image_get_volume_id(const IsoImage *image)
|
||||
{
|
||||
if (image->volume_id == NULL)
|
||||
return "";
|
||||
return image->volume_id;
|
||||
}
|
||||
|
||||
@ -199,6 +244,8 @@ void iso_image_set_publisher_id(IsoImage *image, const char *publisher_id)
|
||||
|
||||
const char *iso_image_get_publisher_id(const IsoImage *image)
|
||||
{
|
||||
if (image->publisher_id == NULL)
|
||||
return "";
|
||||
return image->publisher_id;
|
||||
}
|
||||
|
||||
@ -211,6 +258,8 @@ void iso_image_set_data_preparer_id(IsoImage *image,
|
||||
|
||||
const char *iso_image_get_data_preparer_id(const IsoImage *image)
|
||||
{
|
||||
if (image->data_preparer_id == NULL)
|
||||
return "";
|
||||
return image->data_preparer_id;
|
||||
}
|
||||
|
||||
@ -222,6 +271,8 @@ void iso_image_set_system_id(IsoImage *image, const char *system_id)
|
||||
|
||||
const char *iso_image_get_system_id(const IsoImage *image)
|
||||
{
|
||||
if (image->system_id == NULL)
|
||||
return "";
|
||||
return image->system_id;
|
||||
}
|
||||
|
||||
@ -233,6 +284,8 @@ void iso_image_set_application_id(IsoImage *image, const char *application_id)
|
||||
|
||||
const char *iso_image_get_application_id(const IsoImage *image)
|
||||
{
|
||||
if (image->application_id == NULL)
|
||||
return "";
|
||||
return image->application_id;
|
||||
}
|
||||
|
||||
@ -245,6 +298,8 @@ void iso_image_set_copyright_file_id(IsoImage *image,
|
||||
|
||||
const char *iso_image_get_copyright_file_id(const IsoImage *image)
|
||||
{
|
||||
if (image->copyright_file_id == NULL)
|
||||
return "";
|
||||
return image->copyright_file_id;
|
||||
}
|
||||
|
||||
@ -257,6 +312,8 @@ void iso_image_set_abstract_file_id(IsoImage *image,
|
||||
|
||||
const char *iso_image_get_abstract_file_id(const IsoImage *image)
|
||||
{
|
||||
if (image->abstract_file_id == NULL)
|
||||
return "";
|
||||
return image->abstract_file_id;
|
||||
}
|
||||
|
||||
@ -268,6 +325,8 @@ void iso_image_set_biblio_file_id(IsoImage *image, const char *biblio_file_id)
|
||||
|
||||
const char *iso_image_get_biblio_file_id(const IsoImage *image)
|
||||
{
|
||||
if (image->biblio_file_id == NULL)
|
||||
return "";
|
||||
return image->biblio_file_id;
|
||||
}
|
||||
|
||||
@ -275,3 +334,326 @@ int iso_image_get_msg_id(IsoImage *image)
|
||||
{
|
||||
return image->id;
|
||||
}
|
||||
|
||||
int iso_image_get_system_area(IsoImage *img, char system_area_data[32768],
|
||||
int *options, int flag)
|
||||
{
|
||||
*options = img->system_area_options;
|
||||
if (img->system_area_data == NULL)
|
||||
return 0;
|
||||
memcpy(system_area_data, img->system_area_data, 32768);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* API */
|
||||
int iso_image_get_session_md5(IsoImage *image, uint32_t *start_lba,
|
||||
uint32_t *end_lba, char md5[16], int flag)
|
||||
{
|
||||
if (image->checksum_array == NULL || image->checksum_idx_count < 1)
|
||||
return 0;
|
||||
*start_lba = image->checksum_start_lba;
|
||||
*end_lba = image->checksum_end_lba;
|
||||
memcpy(md5, image->checksum_array, 16);
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_image_set_checksums(IsoImage *image, char *checksum_array,
|
||||
uint32_t start_lba, uint32_t end_lba,
|
||||
uint32_t idx_count, int flag)
|
||||
{
|
||||
iso_image_free_checksums(image, 0);
|
||||
image->checksum_array = checksum_array;
|
||||
image->checksum_start_lba = start_lba;
|
||||
image->checksum_end_lba = end_lba;
|
||||
image->checksum_idx_count = idx_count;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iso_image_generator_is_running(IsoImage *image)
|
||||
{
|
||||
return image->generator_is_running;
|
||||
}
|
||||
|
||||
|
||||
/* API */
|
||||
int iso_image_add_mips_boot_file(IsoImage *image, char *path, int flag)
|
||||
{
|
||||
if (image->num_mips_boot_files >= 15)
|
||||
return ISO_BOOT_TOO_MANY_MIPS;
|
||||
image->mips_boot_file_paths[image->num_mips_boot_files] = strdup(path);
|
||||
if (image->mips_boot_file_paths[image->num_mips_boot_files] == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
image->num_mips_boot_files++;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/* API */
|
||||
int iso_image_get_mips_boot_files(IsoImage *image, char *paths[15], int flag)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < image->num_mips_boot_files; i++)
|
||||
paths[i] = image->mips_boot_file_paths[i];
|
||||
for (; i < 15; i++)
|
||||
paths[i] = NULL;
|
||||
return image->num_mips_boot_files;
|
||||
}
|
||||
|
||||
/* API */
|
||||
int iso_image_give_up_mips_boot(IsoImage *image, int flag)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < image->num_mips_boot_files; i++)
|
||||
if (image->mips_boot_file_paths[i] != NULL) {
|
||||
free(image->mips_boot_file_paths[i]);
|
||||
image->mips_boot_file_paths[i] = NULL;
|
||||
}
|
||||
image->num_mips_boot_files = 0;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
122
libisofs/image.h
122
libisofs/image.h
@ -1,9 +1,11 @@
|
||||
/*
|
||||
* 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.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_IMAGE_H_
|
||||
#define LIBISO_IMAGE_H_
|
||||
@ -13,6 +15,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
|
||||
@ -43,6 +53,19 @@ struct Iso_Image
|
||||
/* el-torito boot catalog */
|
||||
struct el_torito_boot_catalog *bootcat;
|
||||
|
||||
/* Eventually loaded system area data, or NULL */
|
||||
char *system_area_data;
|
||||
/* Prescribed/detected options, see iso_write_opts_set_system_area() */
|
||||
int system_area_options;
|
||||
|
||||
/*
|
||||
* Up to 15 boot files can be referred by a MIPS Big Endian Volume Header.
|
||||
The mips_boot_file_paths are ISO 9660 Rock Ridge paths.
|
||||
*/
|
||||
int num_mips_boot_files;
|
||||
char *mips_boot_file_paths[15]; /* ISO 9660 Rock Ridge Paths */
|
||||
|
||||
|
||||
/* image identifier, for message origin identifier */
|
||||
int id;
|
||||
|
||||
@ -76,6 +99,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 +144,87 @@ 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;
|
||||
|
||||
/**
|
||||
* Array of MD5 checksums as announced by xattr "isofs.ca" of the
|
||||
* root node. Array element 0 contains an overall image checksum for the
|
||||
* block range checksum_start_lba,checksum_end_lba. Element size is
|
||||
* 16 bytes. IsoFile objects in the image may have xattr "isofs.cx"
|
||||
* which gives their index in checksum_array.
|
||||
*/
|
||||
uint32_t checksum_start_lba;
|
||||
uint32_t checksum_end_lba;
|
||||
uint32_t checksum_idx_count;
|
||||
char *checksum_array;
|
||||
|
||||
/**
|
||||
* Whether a write run has been started by iso_image_create_burn_source()
|
||||
* and has not yet been finished.
|
||||
*/
|
||||
int generator_is_running;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
/* Free the checksum array of an image and reset its layout parameters
|
||||
*/
|
||||
int iso_image_free_checksums(IsoImage *image, int flag);
|
||||
|
||||
|
||||
/* Equip an ISO image with a new checksum array buffer (after isofs.ca and
|
||||
isofs.cx have already been adjusted).
|
||||
*/
|
||||
int iso_image_set_checksums(IsoImage *image, char *checksum_array,
|
||||
uint32_t start_lba, uint32_t end_lba,
|
||||
uint32_t idx_count, int flag);
|
||||
|
||||
|
||||
#endif /*LIBISO_IMAGE_H_*/
|
||||
|
@ -1,17 +1,24 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "iso1999.h"
|
||||
#include "messages.h"
|
||||
#include "writer.h"
|
||||
#include "image.h"
|
||||
#include "filesrc.h"
|
||||
#include "eltorito.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -32,7 +39,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 +57,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;
|
||||
}
|
||||
|
||||
@ -68,7 +75,7 @@ void iso1999_node_free(Iso1999Node *node)
|
||||
return;
|
||||
}
|
||||
if (node->type == ISO1999_DIR) {
|
||||
int i;
|
||||
size_t i;
|
||||
for (i = 0; i < node->info.dir->nchildren; i++) {
|
||||
iso1999_node_free(node->info.dir->children[i]);
|
||||
}
|
||||
@ -117,12 +124,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 +168,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 +194,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 +242,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 +284,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];
|
||||
@ -294,33 +309,35 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
Iso1999Node **children;
|
||||
IsoHTable *table;
|
||||
int need_sort = 0;
|
||||
char *full_name = NULL, *tmp = NULL;
|
||||
|
||||
LIBISO_ALLOC_MEM(full_name, char, 208);
|
||||
LIBISO_ALLOC_MEM(tmp, char, 208);
|
||||
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;
|
||||
goto ex;
|
||||
}
|
||||
for (i = 0; i < nchildren; ++i) {
|
||||
char *name = children[i]->name;
|
||||
ret = iso_htable_add(table, name, name);
|
||||
if (ret < 0) {
|
||||
goto mangle_cleanup;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nchildren; ++i) {
|
||||
char *name, *ext;
|
||||
char full_name[208];
|
||||
int max; /* computed max len for name, without extension */
|
||||
int j = i;
|
||||
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 +347,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 +362,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,20 +375,20 @@ 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;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
/* ok, reduce name by digits */
|
||||
@ -385,7 +402,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
}
|
||||
max = 207 - digits;
|
||||
name = full_name;
|
||||
if (max < strlen(name)) {
|
||||
if ((size_t) max < strlen(name)) {
|
||||
name[max] = '\0';
|
||||
}
|
||||
/* let ext be an empty string */
|
||||
@ -395,7 +412,6 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
ok = 1;
|
||||
/* change name of each file */
|
||||
for (k = i; k <= j; ++k) {
|
||||
char tmp[208];
|
||||
char fmt[16];
|
||||
if (dot != NULL) {
|
||||
sprintf(fmt, "%%s%%0%dd.%%s", digits);
|
||||
@ -418,7 +434,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
char *new = strdup(tmp);
|
||||
if (new == NULL) {
|
||||
ret = ISO_OUT_OF_MEM;
|
||||
goto mangle_cleanup;
|
||||
goto ex;
|
||||
}
|
||||
iso_msg_debug(img->image->id, "\"%s\" renamed to \"%s\"",
|
||||
children[k]->name, new);
|
||||
@ -428,7 +444,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
|
||||
*/
|
||||
@ -446,7 +462,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
}
|
||||
if (digits == 8) {
|
||||
ret = ISO_MANGLE_TOO_MUCH_FILES;
|
||||
goto mangle_cleanup;
|
||||
goto ex;
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
@ -459,9 +475,11 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
|
||||
}
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
|
||||
mangle_cleanup : ;
|
||||
|
||||
ex:;
|
||||
iso_htable_destroy(table, NULL);
|
||||
LIBISO_FREE_MEM(tmp);
|
||||
LIBISO_FREE_MEM(full_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -494,7 +512,7 @@ int iso1999_tree_create(Ecma119Image *t)
|
||||
{
|
||||
int ret;
|
||||
Iso1999Node *root;
|
||||
|
||||
|
||||
if (t == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
@ -507,7 +525,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 +567,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 +649,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 +670,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 +678,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 +698,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 +720,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;
|
||||
iso_bb(rec->vol_seq_number, 1, 2);
|
||||
rec->flags[0] = ((node->type == ISO1999_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
||||
iso_bb(rec->vol_seq_number, (uint32_t) 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,25 +766,25 @@ 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);
|
||||
|
||||
iso_bb(vol.vol_space_size, t->vol_space_size, 4);
|
||||
iso_bb(vol.vol_set_size, 1, 2);
|
||||
iso_bb(vol.vol_seq_number, 1, 2);
|
||||
iso_bb(vol.block_size, BLOCK_SIZE, 2);
|
||||
iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
|
||||
iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
|
||||
iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
|
||||
iso_bb(vol.path_table_size, t->iso1999_path_table_size, 4);
|
||||
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);
|
||||
@ -790,45 +815,51 @@ static
|
||||
int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
|
||||
{
|
||||
int ret;
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
uint8_t *buffer = NULL;
|
||||
size_t i;
|
||||
size_t fi_len, len;
|
||||
|
||||
/* buf will point to current write position on buffer */
|
||||
uint8_t *buf = buffer;
|
||||
uint8_t *buf;
|
||||
|
||||
/* initialize buffer with 0s */
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
|
||||
/* 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) {
|
||||
goto ex;
|
||||
}
|
||||
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 */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -861,13 +892,17 @@ static
|
||||
int write_path_table(Ecma119Image *t, Iso1999Node **pathlist, int l_type)
|
||||
{
|
||||
size_t i, len;
|
||||
uint8_t buf[256]; /* 256 is just a convenient size larger enought */
|
||||
uint8_t *buf = NULL;
|
||||
struct ecma119_path_table_record *rec;
|
||||
void (*write_int)(uint8_t*, uint32_t, int);
|
||||
Iso1999Node *dir;
|
||||
uint32_t path_table_size;
|
||||
int parent = 0;
|
||||
int ret= ISO_SUCCESS;
|
||||
uint8_t *zeros = NULL;
|
||||
|
||||
/* 256 is just a convenient size large enought */
|
||||
LIBISO_ALLOC_MEM(buf, uint8_t, 256);
|
||||
|
||||
path_table_size = 0;
|
||||
write_int = l_type ? iso_lsb : iso_msb;
|
||||
@ -894,7 +929,7 @@ int write_path_table(Ecma119Image *t, Iso1999Node **pathlist, int l_type)
|
||||
ret = iso_write(t, buf, len);
|
||||
if (ret < 0) {
|
||||
/* error */
|
||||
return ret;
|
||||
goto ex;
|
||||
}
|
||||
path_table_size += len;
|
||||
}
|
||||
@ -902,11 +937,14 @@ int write_path_table(Ecma119Image *t, Iso1999Node **pathlist, int l_type)
|
||||
/* we need to fill the last block with zeros */
|
||||
path_table_size %= BLOCK_SIZE;
|
||||
if (path_table_size) {
|
||||
uint8_t zeros[BLOCK_SIZE];
|
||||
LIBISO_ALLOC_MEM(zeros, uint8_t, BLOCK_SIZE);
|
||||
len = BLOCK_SIZE - path_table_size;
|
||||
memset(zeros, 0, len);
|
||||
ret = iso_write(t, zeros, len);
|
||||
}
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(zeros);
|
||||
LIBISO_FREE_MEM(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1000,10 +1038,11 @@ 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) {
|
||||
free((char *) writer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -1,18 +1,27 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "joliet.h"
|
||||
#include "messages.h"
|
||||
#include "writer.h"
|
||||
#include "image.h"
|
||||
#include "filesrc.h"
|
||||
#include "eltorito.h"
|
||||
#include "libisofs.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -35,19 +44,18 @@ int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name)
|
||||
iso_msg_debug(t->image->id, "Can't convert %s", iso->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO #00022 : support relaxed constraints in joliet filenames */
|
||||
if (iso->type == LIBISO_DIR) {
|
||||
jname = iso_j_dir_id(ucs_name);
|
||||
jname = iso_j_dir_id(ucs_name, t->joliet_long_names << 1);
|
||||
} else {
|
||||
jname = iso_j_file_id(ucs_name);
|
||||
jname = iso_j_file_id(ucs_name,
|
||||
(t->joliet_long_names << 1) | !!(t->no_force_dots & 2));
|
||||
}
|
||||
free(ucs_name);
|
||||
if (jname != NULL) {
|
||||
*name = jname;
|
||||
return ISO_SUCCESS;
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* only possible if mem error, as check for empty names is done
|
||||
* in public tree
|
||||
*/
|
||||
@ -62,7 +70,7 @@ void joliet_node_free(JolietNode *node)
|
||||
return;
|
||||
}
|
||||
if (node->type == JOLIET_DIR) {
|
||||
int i;
|
||||
size_t i;
|
||||
for (i = 0; i < node->info.dir->nchildren; i++) {
|
||||
joliet_node_free(node->info.dir->children[i]);
|
||||
}
|
||||
@ -111,11 +119,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 +163,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 +188,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 +240,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 Ridge tree.", ipath, (iso->type == LIBISO_SYMLINK ?
|
||||
"Symlinks" : "Special files"));
|
||||
free(ipath);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
@ -257,12 +275,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 +304,32 @@ 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];
|
||||
/* was: The only caller of this function allocates dest
|
||||
with 66 elements and limits digits to < 8
|
||||
But this does not match the usage of nstr which has to take
|
||||
the decimal representation of an int.
|
||||
*/
|
||||
|
||||
if (digits >= 8)
|
||||
return ISO_ASSERT_FAILURE;
|
||||
|
||||
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 */
|
||||
@ -319,19 +345,26 @@ static
|
||||
int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
{
|
||||
int ret;
|
||||
int i, nchildren;
|
||||
int i, nchildren, maxchar = 64;
|
||||
JolietNode **children;
|
||||
IsoHTable *table;
|
||||
int need_sort = 0;
|
||||
uint16_t *full_name = NULL;
|
||||
uint16_t *tmp = NULL;
|
||||
|
||||
LIBISO_ALLOC_MEM(full_name, uint16_t, LIBISO_JOLIET_NAME_MAX);
|
||||
LIBISO_ALLOC_MEM(tmp, uint16_t, LIBISO_JOLIET_NAME_MAX);
|
||||
nchildren = dir->info.dir->nchildren;
|
||||
children = dir->info.dir->children;
|
||||
|
||||
|
||||
if (t->joliet_long_names)
|
||||
maxchar = 103;
|
||||
|
||||
/* 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;
|
||||
goto ex;
|
||||
}
|
||||
for (i = 0; i < nchildren; ++i) {
|
||||
uint16_t *name = children[i]->name;
|
||||
@ -343,13 +376,12 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
|
||||
for (i = 0; i < nchildren; ++i) {
|
||||
uint16_t *name, *ext;
|
||||
uint16_t full_name[66];
|
||||
int max; /* computed max len for name, without extension */
|
||||
int j = i;
|
||||
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 +391,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 < 8 */
|
||||
|
||||
while (digits < 8) {
|
||||
int ok, k;
|
||||
uint16_t *dot;
|
||||
@ -374,7 +408,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;
|
||||
@ -383,21 +417,21 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
ext = dot + 1;
|
||||
|
||||
extlen = ucslen(ext);
|
||||
max = 65 - extlen - 1 - digits;
|
||||
max = maxchar + 1 - 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 = 66 - extlen - 1 - digits;
|
||||
max = maxchar + 2 - 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;
|
||||
@ -410,13 +444,13 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
} else {
|
||||
/* Directory, or file without extension */
|
||||
if (children[i]->type == JOLIET_DIR) {
|
||||
max = 65 - digits;
|
||||
max = maxchar + 1 - digits;
|
||||
dot = NULL; /* dots have no meaning in dirs */
|
||||
} else {
|
||||
max = 65 - digits;
|
||||
max = maxchar + 1 - digits;
|
||||
}
|
||||
name = full_name;
|
||||
if (max < ucslen(name)) {
|
||||
if ((size_t) max < ucslen(name)) {
|
||||
name[max] = 0;
|
||||
}
|
||||
/* let ext be an empty string */
|
||||
@ -426,7 +460,6 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
ok = 1;
|
||||
/* change name of each file */
|
||||
for (k = i; k <= j; ++k) {
|
||||
uint16_t tmp[66];
|
||||
while (1) {
|
||||
ret = joliet_create_mangled_name(tmp, name, digits,
|
||||
change, ext);
|
||||
@ -455,7 +488,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,9 +519,12 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
|
||||
}
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
|
||||
|
||||
mangle_cleanup : ;
|
||||
ex:;
|
||||
iso_htable_destroy(table, NULL);
|
||||
LIBISO_FREE_MEM(tmp);
|
||||
LIBISO_FREE_MEM(full_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -521,7 +557,7 @@ int joliet_tree_create(Ecma119Image *t)
|
||||
{
|
||||
int ret;
|
||||
JolietNode *root;
|
||||
|
||||
|
||||
if (t == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
@ -534,19 +570,21 @@ int joliet_tree_create(Ecma119Image *t)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* the Joliet tree is stored in Ecma119Image target */
|
||||
t->joliet_root = root;
|
||||
if (t->eff_partition_offset > 0) {
|
||||
t->j_part_root = root;
|
||||
} else {
|
||||
t->joliet_root = root;
|
||||
}
|
||||
|
||||
iso_msg_debug(t->image->id, "Sorting the Joliet tree...");
|
||||
sort_tree(root);
|
||||
|
||||
iso_msg_debug(t->image->id, "Mangling Joliet names...");
|
||||
ret = mangle_tree(t, t->joliet_root);
|
||||
if (ret < 0) {
|
||||
ret = mangle_tree(t, root);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
@ -558,7 +596,7 @@ size_t calc_dirent_len(Ecma119Image *t, JolietNode *n)
|
||||
{
|
||||
/* note than name len is always even, so we always need the pad byte */
|
||||
int ret = n->name ? ucslen(n->name) * 2 + 34 : 34;
|
||||
if (n->type == JOLIET_FILE && !t->omit_version_numbers) {
|
||||
if (n->type == JOLIET_FILE && !(t->omit_version_numbers & 3)) {
|
||||
/* take into account version numbers */
|
||||
ret += 4;
|
||||
}
|
||||
@ -580,20 +618,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);
|
||||
@ -648,6 +691,7 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
{
|
||||
Ecma119Image *t;
|
||||
uint32_t path_table_size;
|
||||
size_t ndirs;
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
@ -671,13 +715,31 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
|
||||
t->joliet_path_table_size = path_table_size;
|
||||
|
||||
if (t->partition_offset > 0) {
|
||||
/* Take into respect second directory tree */
|
||||
ndirs = t->joliet_ndirs;
|
||||
t->joliet_ndirs = 0;
|
||||
calc_dir_pos(t, t->j_part_root);
|
||||
if (t->joliet_ndirs != ndirs) {
|
||||
iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
|
||||
"Number of directories differs in Joliet partiton_tree");
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
/* Take into respect second set of path tables */
|
||||
path_table_size = calc_path_table_size(t->j_part_root);
|
||||
t->j_part_l_path_table_pos = t->curblock;
|
||||
t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
|
||||
t->j_part_m_path_table_pos = t->curblock;
|
||||
t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
|
||||
}
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +748,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;
|
||||
|
||||
@ -700,7 +763,7 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
|
||||
|
||||
memcpy(rec->file_id, name, len_fi);
|
||||
|
||||
if (node->type == JOLIET_FILE && !t->omit_version_numbers) {
|
||||
if (node->type == JOLIET_FILE && !(t->omit_version_numbers & 3)) {
|
||||
len_dr += 4;
|
||||
rec->file_id[len_fi++] = 0;
|
||||
rec->file_id[len_fi++] = ';';
|
||||
@ -713,12 +776,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;
|
||||
@ -731,11 +795,11 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
|
||||
node = node->parent;
|
||||
|
||||
rec->len_dr[0] = len_dr;
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->block, block - t->eff_partition_offset, 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;
|
||||
iso_bb(rec->vol_seq_number, 1, 2);
|
||||
rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
||||
iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
}
|
||||
|
||||
@ -748,26 +812,25 @@ 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] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int joliet_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
{
|
||||
IsoImage *image;
|
||||
@ -805,24 +868,33 @@ 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);
|
||||
|
||||
iso_bb(vol.vol_space_size, t->vol_space_size, 4);
|
||||
iso_bb(vol.vol_set_size, 1, 2);
|
||||
iso_bb(vol.vol_seq_number, 1, 2);
|
||||
iso_bb(vol.block_size, BLOCK_SIZE, 2);
|
||||
iso_bb(vol.vol_space_size, t->vol_space_size - t->eff_partition_offset,
|
||||
4);
|
||||
iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
|
||||
iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
|
||||
iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
|
||||
iso_bb(vol.path_table_size, t->joliet_path_table_size, 4);
|
||||
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);
|
||||
if (t->eff_partition_offset > 0) {
|
||||
/* Point to second tables and second root */
|
||||
iso_lsb(vol.l_path_table_pos,
|
||||
t->j_part_l_path_table_pos - t->eff_partition_offset, 4);
|
||||
iso_msb(vol.m_path_table_pos,
|
||||
t->j_part_m_path_table_pos - t->eff_partition_offset, 4);
|
||||
write_one_dir_record(t, t->j_part_root, 0, vol.root_dir_record, 1, 0);
|
||||
} else {
|
||||
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, 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);
|
||||
@ -853,48 +925,57 @@ static
|
||||
int write_one_dir(Ecma119Image *t, JolietNode *dir)
|
||||
{
|
||||
int ret;
|
||||
uint8_t buffer[BLOCK_SIZE];
|
||||
uint8_t *buffer = NULL;
|
||||
size_t i;
|
||||
size_t fi_len, len;
|
||||
|
||||
/* buf will point to current write position on buffer */
|
||||
uint8_t *buf = buffer;
|
||||
uint8_t *buf;
|
||||
|
||||
/* initialize buffer with 0s */
|
||||
memset(buffer, 0, BLOCK_SIZE);
|
||||
LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
|
||||
buf = buffer;
|
||||
|
||||
/* 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 */
|
||||
fi_len = ucslen(child->name) * 2;
|
||||
len = fi_len + 34;
|
||||
if (child->type == JOLIET_FILE && !t->omit_version_numbers) {
|
||||
if (child->type == JOLIET_FILE && !(t->omit_version_numbers & 3)) {
|
||||
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) {
|
||||
goto ex;
|
||||
}
|
||||
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 */
|
||||
ret = iso_write(t, buffer, BLOCK_SIZE);
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -927,14 +1008,18 @@ static
|
||||
int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type)
|
||||
{
|
||||
size_t i, len;
|
||||
uint8_t buf[256]; /* 256 is just a convenient size larger enought */
|
||||
uint8_t *buf = NULL;
|
||||
struct ecma119_path_table_record *rec;
|
||||
void (*write_int)(uint8_t*, uint32_t, int);
|
||||
JolietNode *dir;
|
||||
uint32_t path_table_size;
|
||||
int parent = 0;
|
||||
int ret= ISO_SUCCESS;
|
||||
uint8_t *zeros = NULL;
|
||||
|
||||
/* 256 is just a convenient size large enought */
|
||||
LIBISO_ALLOC_MEM(buf, uint8_t, 256);
|
||||
LIBISO_ALLOC_MEM(zeros, uint8_t, BLOCK_SIZE);
|
||||
path_table_size = 0;
|
||||
write_int = l_type ? iso_lsb : iso_msb;
|
||||
|
||||
@ -951,7 +1036,8 @@ int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type)
|
||||
rec = (struct ecma119_path_table_record*) buf;
|
||||
rec->len_di[0] = dir->parent ? (uint8_t) ucslen(dir->name) * 2 : 1;
|
||||
rec->len_xa[0] = 0;
|
||||
write_int(rec->block, dir->info.dir->block, 4);
|
||||
write_int(rec->block, dir->info.dir->block - t->eff_partition_offset,
|
||||
4);
|
||||
write_int(rec->parent, parent + 1, 2);
|
||||
if (dir->parent) {
|
||||
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
|
||||
@ -960,7 +1046,7 @@ int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type)
|
||||
ret = iso_write(t, buf, len);
|
||||
if (ret < 0) {
|
||||
/* error */
|
||||
return ret;
|
||||
goto ex;
|
||||
}
|
||||
path_table_size += len;
|
||||
}
|
||||
@ -968,11 +1054,13 @@ int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type)
|
||||
/* we need to fill the last block with zeros */
|
||||
path_table_size %= BLOCK_SIZE;
|
||||
if (path_table_size) {
|
||||
uint8_t zeros[BLOCK_SIZE];
|
||||
len = BLOCK_SIZE - path_table_size;
|
||||
memset(zeros, 0, len);
|
||||
ret = iso_write(t, zeros, len);
|
||||
}
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(zeros);
|
||||
LIBISO_FREE_MEM(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -990,7 +1078,12 @@ int write_path_tables(Ecma119Image *t)
|
||||
if (pathlist == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
pathlist[0] = t->joliet_root;
|
||||
|
||||
if (t->eff_partition_offset > 0) {
|
||||
pathlist[0] = t->j_part_root;
|
||||
} else {
|
||||
pathlist[0] = t->joliet_root;
|
||||
}
|
||||
cur = 1;
|
||||
|
||||
for (i = 0; i < t->joliet_ndirs; i++) {
|
||||
@ -1018,18 +1111,21 @@ int write_path_tables(Ecma119Image *t)
|
||||
}
|
||||
|
||||
static
|
||||
int joliet_writer_write_data(IsoImageWriter *writer)
|
||||
int joliet_writer_write_dirs(IsoImageWriter *writer)
|
||||
{
|
||||
int ret;
|
||||
Ecma119Image *t;
|
||||
JolietNode *root;
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
t = writer->target;
|
||||
|
||||
/* first of all, we write the directory structure */
|
||||
ret = write_dirs(t, t->joliet_root);
|
||||
if (t->eff_partition_offset > 0) {
|
||||
root = t->j_part_root;
|
||||
} else {
|
||||
root = t->joliet_root;
|
||||
}
|
||||
ret = write_dirs(t, root);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -1040,12 +1136,40 @@ int joliet_writer_write_data(IsoImageWriter *writer)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int joliet_writer_write_data(IsoImageWriter *writer)
|
||||
{
|
||||
int ret;
|
||||
Ecma119Image *t;
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
t = writer->target;
|
||||
|
||||
ret = joliet_writer_write_dirs(writer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (t->partition_offset > 0) {
|
||||
t->eff_partition_offset = t->partition_offset;
|
||||
ret = joliet_writer_write_dirs(writer);
|
||||
t->eff_partition_offset = 0;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
int joliet_writer_free_data(IsoImageWriter *writer)
|
||||
{
|
||||
/* free the Joliet tree */
|
||||
Ecma119Image *t = writer->target;
|
||||
joliet_node_free(t->joliet_root);
|
||||
if (t->j_part_root != NULL)
|
||||
joliet_node_free(t->j_part_root);
|
||||
t->j_part_root = NULL;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1069,12 +1193,23 @@ int joliet_writer_create(Ecma119Image *target)
|
||||
iso_msg_debug(target->image->id, "Creating low level Joliet tree...");
|
||||
ret = joliet_tree_create(target);
|
||||
if (ret < 0) {
|
||||
free((char *) writer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* add this writer to image */
|
||||
target->writers[target->nwriters++] = writer;
|
||||
|
||||
if(target->partition_offset > 0) {
|
||||
/* Create second tree */
|
||||
target->eff_partition_offset = target->partition_offset;
|
||||
ret = joliet_tree_create(target);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
target->eff_partition_offset = 0;
|
||||
}
|
||||
|
||||
/* we need the volume descriptor */
|
||||
target->curblock++;
|
||||
return ISO_SUCCESS;
|
||||
|
@ -3,8 +3,9 @@
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -17,6 +18,10 @@
|
||||
#include "libisofs.h"
|
||||
#include "ecma119.h"
|
||||
|
||||
/* was formerly 66 = 64 + 2. Now 105 = 103 + 2.
|
||||
*/
|
||||
#define LIBISO_JOLIET_NAME_MAX 105
|
||||
|
||||
enum joliet_node_type {
|
||||
JOLIET_FILE,
|
||||
JOLIET_DIR
|
||||
@ -53,4 +58,10 @@ struct joliet_node
|
||||
*/
|
||||
int joliet_writer_create(Ecma119Image *target);
|
||||
|
||||
|
||||
/* Not to be called but only for comparison with target->writers[i]
|
||||
*/
|
||||
int joliet_writer_write_vol_desc(IsoImageWriter *writer);
|
||||
|
||||
|
||||
#endif /* LIBISO_JOLIET_H */
|
||||
|
@ -1,10 +1,14 @@
|
||||
|
||||
/* 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
|
||||
provided under GPL version 2 or later
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@ -268,10 +272,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 +288,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 +314,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,8 +1,8 @@
|
||||
|
||||
/* 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
|
||||
provided under GPL version 2 or later
|
||||
*/
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
5158
libisofs/libisofs.h
5158
libisofs/libisofs.h
File diff suppressed because it is too large
Load Diff
315
libisofs/libisofs.ver
Normal file
315
libisofs/libisofs.ver
Normal file
@ -0,0 +1,315 @@
|
||||
LIBISOFS6 {
|
||||
global:
|
||||
aaip_xinfo_cloner;
|
||||
aaip_xinfo_func;
|
||||
el_torito_get_bootable;
|
||||
el_torito_get_boot_media_type;
|
||||
el_torito_get_boot_platform_id;
|
||||
el_torito_get_id_string;
|
||||
el_torito_get_isolinux_options;
|
||||
el_torito_get_load_seg;
|
||||
el_torito_get_load_size;
|
||||
el_torito_get_selection_crit;
|
||||
el_torito_patch_isolinux_image;
|
||||
el_torito_seems_boot_info_table;
|
||||
el_torito_set_boot_platform_id;
|
||||
el_torito_set_id_string;
|
||||
el_torito_set_isolinux_options;
|
||||
el_torito_set_load_seg;
|
||||
el_torito_set_load_size;
|
||||
el_torito_set_no_bootable;
|
||||
el_torito_set_selection_crit;
|
||||
iso_data_source_new_from_file;
|
||||
iso_data_source_ref;
|
||||
iso_data_source_unref;
|
||||
iso_dir_add_node;
|
||||
iso_dir_find_children;
|
||||
iso_dir_get_children;
|
||||
iso_dir_get_children_count;
|
||||
iso_dir_get_node;
|
||||
iso_dir_iter_free;
|
||||
iso_dir_iter_has_next;
|
||||
iso_dir_iter_next;
|
||||
iso_dir_iter_remove;
|
||||
iso_dir_iter_take;
|
||||
iso_error_get_code;
|
||||
iso_error_get_priority;
|
||||
iso_error_get_severity;
|
||||
iso_error_to_msg;
|
||||
iso_file_add_external_filter;
|
||||
iso_file_add_gzip_filter;
|
||||
iso_file_add_zisofs_filter;
|
||||
iso_file_get_md5;
|
||||
iso_file_get_old_image_lba;
|
||||
iso_file_get_old_image_sections;
|
||||
iso_file_get_size;
|
||||
iso_file_get_sort_weight;
|
||||
iso_file_get_stream;
|
||||
iso_file_make_md5;
|
||||
iso_file_remove_filter;
|
||||
iso_file_source_access;
|
||||
iso_file_source_close;
|
||||
iso_file_source_get_aa_string;
|
||||
iso_file_source_get_filesystem;
|
||||
iso_file_source_get_name;
|
||||
iso_file_source_get_path;
|
||||
iso_file_source_lseek;
|
||||
iso_file_source_lstat;
|
||||
iso_file_source_open;
|
||||
iso_file_source_read;
|
||||
iso_file_source_readdir;
|
||||
iso_file_source_readlink;
|
||||
iso_file_source_ref;
|
||||
iso_file_source_stat;
|
||||
iso_file_source_unref;
|
||||
iso_filesystem_ref;
|
||||
iso_filesystem_unref;
|
||||
iso_finish;
|
||||
iso_get_local_charset;
|
||||
iso_get_messenger;
|
||||
iso_gzip_get_refcounts;
|
||||
iso_image_add_boot_image;
|
||||
iso_image_add_mips_boot_file;
|
||||
iso_image_attach_data;
|
||||
iso_image_create_burn_source;
|
||||
iso_image_filesystem_new;
|
||||
iso_image_fs_get_abstract_file_id;
|
||||
iso_image_fs_get_application_id;
|
||||
iso_image_fs_get_biblio_file_id;
|
||||
iso_image_fs_get_copyright_file_id;
|
||||
iso_image_fs_get_data_preparer_id;
|
||||
iso_image_fs_get_publisher_id;
|
||||
iso_image_fs_get_system_id;
|
||||
iso_image_fs_get_volset_id;
|
||||
iso_image_fs_get_volume_id;
|
||||
iso_image_generator_is_running;
|
||||
iso_image_get_abstract_file_id;
|
||||
iso_image_get_all_boot_imgs;
|
||||
iso_image_get_application_id;
|
||||
iso_image_get_attached_data;
|
||||
iso_image_get_biblio_file_id;
|
||||
iso_image_get_bootcat;
|
||||
iso_image_get_boot_image;
|
||||
iso_image_get_copyright_file_id;
|
||||
iso_image_get_data_preparer_id;
|
||||
iso_image_get_mips_boot_files;
|
||||
iso_image_get_msg_id;
|
||||
iso_image_get_publisher_id;
|
||||
iso_image_get_root;
|
||||
iso_image_get_session_md5;
|
||||
iso_image_get_system_area;
|
||||
iso_image_get_system_id;
|
||||
iso_image_get_volset_id;
|
||||
iso_image_get_volume_id;
|
||||
iso_image_give_up_mips_boot;
|
||||
iso_image_import;
|
||||
iso_image_new;
|
||||
iso_image_ref;
|
||||
iso_image_remove_boot_image;
|
||||
iso_image_set_abstract_file_id;
|
||||
iso_image_set_application_id;
|
||||
iso_image_set_biblio_file_id;
|
||||
iso_image_set_boot_catalog_hidden;
|
||||
iso_image_set_boot_catalog_weight;
|
||||
iso_image_set_boot_image;
|
||||
iso_image_set_copyright_file_id;
|
||||
iso_image_set_data_preparer_id;
|
||||
iso_image_set_ignore_aclea;
|
||||
iso_image_set_publisher_id;
|
||||
iso_image_set_system_id;
|
||||
iso_image_set_volset_id;
|
||||
iso_image_set_volume_id;
|
||||
iso_image_unref;
|
||||
iso_image_update_sizes;
|
||||
iso_init;
|
||||
iso_init_with_flag;
|
||||
iso_lib_is_compatible;
|
||||
iso_lib_version;
|
||||
iso_local_get_acl_text;
|
||||
iso_local_get_attrs;
|
||||
iso_local_get_perms_wo_acl;
|
||||
iso_local_set_acl_text;
|
||||
iso_local_set_attrs;
|
||||
iso_md5_clone;
|
||||
iso_md5_compute;
|
||||
iso_md5_end;
|
||||
iso_md5_match;
|
||||
iso_md5_start;
|
||||
iso_memory_stream_new;
|
||||
iso_msgs_submit;
|
||||
iso_new_find_conditions_and;
|
||||
iso_new_find_conditions_atime;
|
||||
iso_new_find_conditions_ctime;
|
||||
iso_new_find_conditions_gid;
|
||||
iso_new_find_conditions_mode;
|
||||
iso_new_find_conditions_mtime;
|
||||
iso_new_find_conditions_name;
|
||||
iso_new_find_conditions_not;
|
||||
iso_new_find_conditions_or;
|
||||
iso_new_find_conditions_uid;
|
||||
iso_node_add_xinfo;
|
||||
iso_node_cmp_ino;
|
||||
iso_node_get_acl_text;
|
||||
iso_node_get_atime;
|
||||
iso_node_get_attrs;
|
||||
iso_node_get_ctime;
|
||||
iso_node_get_gid;
|
||||
iso_node_get_hidden;
|
||||
iso_node_get_mode;
|
||||
iso_node_get_mtime;
|
||||
iso_node_get_name;
|
||||
iso_node_get_next_xinfo;
|
||||
iso_node_get_old_image_lba;
|
||||
iso_node_get_parent;
|
||||
iso_node_get_permissions;
|
||||
iso_node_get_perms_wo_acl;
|
||||
iso_node_get_type;
|
||||
iso_node_get_uid;
|
||||
iso_node_get_xinfo;
|
||||
iso_node_lookup_attr;
|
||||
iso_node_ref;
|
||||
iso_node_remove;
|
||||
iso_node_remove_all_xinfo;
|
||||
iso_node_remove_tree;
|
||||
iso_node_remove_xinfo;
|
||||
iso_node_set_acl_text;
|
||||
iso_node_set_atime;
|
||||
iso_node_set_attrs;
|
||||
iso_node_set_ctime;
|
||||
iso_node_set_gid;
|
||||
iso_node_set_hidden;
|
||||
iso_node_set_mtime;
|
||||
iso_node_set_name;
|
||||
iso_node_set_permissions;
|
||||
iso_node_set_sort_weight;
|
||||
iso_node_set_uid;
|
||||
iso_node_take;
|
||||
iso_node_unref;
|
||||
iso_node_xinfo_get_cloner;
|
||||
iso_node_xinfo_make_clonable;
|
||||
iso_node_zf_by_magic;
|
||||
iso_obtain_msgs;
|
||||
iso_read_image_features_destroy;
|
||||
iso_read_image_features_get_size;
|
||||
iso_read_image_features_has_eltorito;
|
||||
iso_read_image_features_has_iso1999;
|
||||
iso_read_image_features_has_joliet;
|
||||
iso_read_image_features_has_rockridge;
|
||||
iso_read_opts_auto_input_charset;
|
||||
iso_read_opts_free;
|
||||
iso_read_opts_load_system_area;
|
||||
iso_read_opts_new;
|
||||
iso_read_opts_set_default_gid;
|
||||
iso_read_opts_set_default_permissions;
|
||||
iso_read_opts_set_default_uid;
|
||||
iso_read_opts_set_input_charset;
|
||||
iso_read_opts_set_new_inos;
|
||||
iso_read_opts_set_no_aaip;
|
||||
iso_read_opts_set_no_iso1999;
|
||||
iso_read_opts_set_no_joliet;
|
||||
iso_read_opts_set_no_md5;
|
||||
iso_read_opts_set_no_rockridge;
|
||||
iso_read_opts_set_preferjoliet;
|
||||
iso_read_opts_set_start_block;
|
||||
iso_ring_buffer_get_status;
|
||||
iso_set_abort_severity;
|
||||
iso_set_local_charset;
|
||||
iso_set_msgs_severities;
|
||||
iso_sev_to_text;
|
||||
iso_special_get_dev;
|
||||
iso_stream_clone;
|
||||
iso_stream_close;
|
||||
iso_stream_cmp_ino;
|
||||
iso_stream_get_external_filter;
|
||||
iso_stream_get_id;
|
||||
iso_stream_get_input_stream;
|
||||
iso_stream_get_size;
|
||||
iso_stream_get_source_path;
|
||||
iso_stream_is_repeatable;
|
||||
iso_stream_open;
|
||||
iso_stream_read;
|
||||
iso_stream_ref;
|
||||
iso_stream_unref;
|
||||
iso_stream_update_size;
|
||||
iso_symlink_get_dest;
|
||||
iso_symlink_set_dest;
|
||||
iso_text_to_sev;
|
||||
iso_tree_add_dir_rec;
|
||||
iso_tree_add_exclude;
|
||||
iso_tree_add_new_cut_out_node;
|
||||
iso_tree_add_new_dir;
|
||||
iso_tree_add_new_file;
|
||||
iso_tree_add_new_node;
|
||||
iso_tree_add_new_special;
|
||||
iso_tree_add_new_symlink;
|
||||
iso_tree_add_node;
|
||||
iso_tree_clone;
|
||||
iso_tree_get_follow_symlinks;
|
||||
iso_tree_get_ignore_hidden;
|
||||
iso_tree_get_ignore_special;
|
||||
iso_tree_get_node_path;
|
||||
iso_tree_get_replace_mode;
|
||||
iso_tree_path_to_node;
|
||||
iso_tree_remove_exclude;
|
||||
iso_tree_set_follow_symlinks;
|
||||
iso_tree_set_ignore_hidden;
|
||||
iso_tree_set_ignore_special;
|
||||
iso_tree_set_replace_mode;
|
||||
iso_tree_set_report_callback;
|
||||
iso_util_decode_md5_tag;
|
||||
iso_write_opts_attach_jte;
|
||||
iso_write_opts_detach_jte;
|
||||
iso_write_opts_free;
|
||||
iso_write_opts_get_data_start;
|
||||
iso_write_opts_new;
|
||||
iso_write_opts_set_aaip;
|
||||
iso_write_opts_set_aaip_susp_1_10;
|
||||
iso_write_opts_set_allow_deep_paths;
|
||||
iso_write_opts_set_allow_dir_id_ext;
|
||||
iso_write_opts_set_allow_full_ascii;
|
||||
iso_write_opts_set_allow_longer_paths;
|
||||
iso_write_opts_set_allow_lowercase;
|
||||
iso_write_opts_set_always_gmt;
|
||||
iso_write_opts_set_appendable;
|
||||
iso_write_opts_set_default_dir_mode;
|
||||
iso_write_opts_set_default_file_mode;
|
||||
iso_write_opts_set_default_gid;
|
||||
iso_write_opts_set_default_timestamp;
|
||||
iso_write_opts_set_default_uid;
|
||||
iso_write_opts_set_dir_rec_mtime;
|
||||
iso_write_opts_set_disc_label;
|
||||
iso_write_opts_set_fifo_size;
|
||||
iso_write_opts_set_hardlinks;
|
||||
iso_write_opts_set_iso1999;
|
||||
iso_write_opts_set_iso_level;
|
||||
iso_write_opts_set_joliet;
|
||||
iso_write_opts_set_joliet_long_names;
|
||||
iso_write_opts_set_joliet_longer_paths;
|
||||
iso_write_opts_set_max_37_char_filenames;
|
||||
iso_write_opts_set_ms_block;
|
||||
iso_write_opts_set_no_force_dots;
|
||||
iso_write_opts_set_old_empty;
|
||||
iso_write_opts_set_omit_version_numbers;
|
||||
iso_write_opts_set_output_charset;
|
||||
iso_write_opts_set_overwrite_buf;
|
||||
iso_write_opts_set_part_offset;
|
||||
iso_write_opts_set_partition_img;
|
||||
iso_write_opts_set_pvd_times;
|
||||
iso_write_opts_set_record_md5;
|
||||
iso_write_opts_set_relaxed_vol_atts;
|
||||
iso_write_opts_set_replace_mode;
|
||||
iso_write_opts_set_replace_timestamps;
|
||||
iso_write_opts_set_rockridge;
|
||||
iso_write_opts_set_rrip_1_10_px_ino;
|
||||
iso_write_opts_set_rrip_version_1_10;
|
||||
iso_write_opts_set_scdbackup_tag;
|
||||
iso_write_opts_set_sort_files;
|
||||
iso_write_opts_set_system_area;
|
||||
iso_write_opts_set_tail_blocks;
|
||||
iso_write_opts_set_untranslated_name_len;
|
||||
iso_write_opts_set_will_cancel;
|
||||
iso_zisofs_get_params;
|
||||
iso_zisofs_get_refcounts;
|
||||
iso_zisofs_set_params;
|
||||
local: *;
|
||||
};
|
458
libisofs/make_isohybrid_mbr.c
Normal file
458
libisofs/make_isohybrid_mbr.c
Normal file
@ -0,0 +1,458 @@
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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 GNU xorriso, this code is under GPLv3+ derived from LGPL.
|
||||
In the context of libisofs this code derives its matching free software
|
||||
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-2010 Thomas Schmitt
|
||||
|
||||
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, uint32_t value, int bits, int flag)
|
||||
{
|
||||
int b;
|
||||
|
||||
for (b = 0; b < bits; b += 8)
|
||||
*((unsigned char *) ((*wpt)++)) = (value >> b) & 0xff;
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Deprecated Function */
|
||||
/* ====================================================================== */
|
||||
|
||||
/*
|
||||
* 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, 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
/* The New MBR Producer */
|
||||
/* ====================================================================== */
|
||||
|
||||
/* The new MBR producer for isohybrid is a slightly generalized version of
|
||||
the deprecated function make_isohybrid_mbr(). It complies to the urge
|
||||
of H.Peter Anvin not to hardcode MBR templates but rather to read a
|
||||
file from the Syslinux tree, and to patch it as was done with the old
|
||||
MBR producer.
|
||||
|
||||
The old algorithm was clarified publicly by the following mail.
|
||||
Changes towards the old algorithm:
|
||||
- 512-byte LBA of boot image is extended to 64 bit (we stay with 32)
|
||||
- check for a magic number is now gone
|
||||
|
||||
The new implementation tries to use similar terms as the mail in order
|
||||
to facilitate its future discussion with Syslinux developers.
|
||||
|
||||
From hpa@zytor.com Thu Apr 1 08:32:52 2010
|
||||
Date: Wed, 31 Mar 2010 14:53:51 -0700
|
||||
From: H. Peter Anvin <hpa@zytor.com>
|
||||
To: For discussion of Syslinux and tftp-hpa <syslinux@zytor.com>
|
||||
Cc: Thomas Schmitt <scdbackup@gmx.net>
|
||||
Subject: Re: [syslinux] port syslinux isohybrid perl script to C
|
||||
|
||||
[...]
|
||||
|
||||
[me:]
|
||||
> Currently i lack of blob and prescriptions.
|
||||
|
||||
The blobs are available in the Syslinux build tree under the names:
|
||||
|
||||
mbr/isohdp[fp]x*.bin
|
||||
|
||||
The default probably should be mbr/isohdppx.bin, but it's ultimately up
|
||||
to the user.
|
||||
|
||||
User definable parameters:
|
||||
|
||||
-> MBR ID (default random 32-bit number,
|
||||
or preserved from previous instance)
|
||||
-> Sector count (default 32, range 1-63)
|
||||
-> Head count (default 64, range 1-256)
|
||||
-> Partition offset (default 0, range 0-64)
|
||||
-> Partition number (default 1, range 1-4)
|
||||
-> Filesystem type (default 0x17, range 1-255)
|
||||
|
||||
Note: the filesystem type is largely arbitrary, in theory it can be any
|
||||
value other than 0x00, 0x05, 0x0f, 0x85, 0xee, or 0xef. 0x17 ("Windows
|
||||
IFS Hidden") seems safeish, some people believe 0x83 (Linux) is better.
|
||||
|
||||
Here is the prescriptions for how to install it:
|
||||
|
||||
All numbers are littleendian. "word" means 16 bits, "dword" means 32
|
||||
bits, "qword" means 64 bits.
|
||||
|
||||
Common subroutine LBA_to_CHS():
|
||||
s = (lba % sector_count) + 1
|
||||
t = (lba / sector_count)
|
||||
h = (t % head_count)
|
||||
c = (t / head_count)
|
||||
|
||||
if (c >= 1024):
|
||||
c = 1023
|
||||
h = head_count
|
||||
s = sector_count
|
||||
|
||||
s = s | ((c & 0x300) >> 2)
|
||||
c = c & 0xff
|
||||
|
||||
write byte h
|
||||
write byte s
|
||||
write byte c
|
||||
|
||||
Main:
|
||||
Pad image_size to a multiple of sector_count*head_count
|
||||
Use the input file unmodified for bytes 0..431
|
||||
write qword boot_lba # Offset 432
|
||||
write dword mbr_id # Offset 440
|
||||
write word 0 # Offset 444
|
||||
|
||||
# Offset 446
|
||||
For each partition entry 1..4:
|
||||
if this_partition != partition_number:
|
||||
write 16 zero bytes
|
||||
else:
|
||||
write byte 0x80
|
||||
write LBA_to_CHS(partition_offset)
|
||||
write byte filesystem_type
|
||||
write LBA_to_CHS(image_size-1)
|
||||
write dword partition_offset
|
||||
write dword image_size
|
||||
|
||||
# Offset 510
|
||||
write word 0xaa55
|
||||
|
||||
Use the input file unmodified for bytes 512..32767
|
||||
(pad with zero as necessary)
|
||||
|
||||
[...]
|
||||
|
||||
-hpa
|
||||
*/
|
||||
|
||||
|
||||
static
|
||||
int lba512chs_to_buf(char **wpt, off_t lba, int head_count, int sector_count)
|
||||
{
|
||||
int s, t, h, c;
|
||||
|
||||
s = (lba % sector_count) + 1;
|
||||
t = (lba / sector_count);
|
||||
h = (t % head_count);
|
||||
c = (t / head_count);
|
||||
if (c >= 1024) {
|
||||
c = 1023;
|
||||
h = head_count; /* >>> not -1 ? Limits head_count to 255 */
|
||||
s = sector_count;
|
||||
}
|
||||
s = s | ((c & 0x300) >> 2);
|
||||
c = c & 0xff;
|
||||
(*((unsigned char **) wpt))[0] = h;
|
||||
(*((unsigned char **) wpt))[1] = s;
|
||||
(*((unsigned char **) wpt))[2] = c;
|
||||
(*wpt)+= 3;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit0= make own random MBR Id from current time
|
||||
*/
|
||||
int make_isolinux_mbr(int32_t *img_blocks, uint32_t boot_lba,
|
||||
uint32_t mbr_id, int head_count, int sector_count,
|
||||
int part_offset, int part_number, int fs_type,
|
||||
uint8_t *buf, int flag)
|
||||
{
|
||||
uint32_t id, part, nominal_part_size;
|
||||
off_t hd_img_blocks, hd_boot_lba;
|
||||
char *wpt;
|
||||
/* For generating a weak random number */
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
hd_img_blocks = ((off_t) *img_blocks) * (off_t) 4;
|
||||
|
||||
/* Padding of image_size to a multiple of sector_count*head_count
|
||||
happens already at compute time and is implemented by
|
||||
an appropriate increase of Ecma119Image->tail_blocks.
|
||||
*/
|
||||
|
||||
wpt = (char *) buf + 432;
|
||||
|
||||
/* write qword boot_lba # Offset 432
|
||||
*/
|
||||
hd_boot_lba = ((off_t) boot_lba) * (off_t) 4;
|
||||
lsb_to_buf(&wpt, hd_boot_lba & 0xffffffff, 32, 0);
|
||||
lsb_to_buf(&wpt, hd_boot_lba >> 32, 32, 0);
|
||||
|
||||
/* write dword mbr_id # Offset 440
|
||||
(here some 32-bit random value with no crypto strength)
|
||||
*/
|
||||
if (flag & 1) {
|
||||
gettimeofday(&tv, &tz);
|
||||
id = 0xffffffff & (tv.tv_sec ^ (tv.tv_usec * 2000));
|
||||
lsb_to_buf(&wpt, id, 32, 0);
|
||||
}
|
||||
|
||||
/* write word 0 # Offset 444
|
||||
*/
|
||||
lsb_to_buf(&wpt, 0, 16, 0);
|
||||
|
||||
/* # Offset 446
|
||||
*/
|
||||
for (part = 1 ; part <= 4; part++) {
|
||||
if ((int) part != part_number) {
|
||||
/* if this_partition != partition_number: write 16 zero bytes */
|
||||
memset(wpt, 0, 16);
|
||||
wpt+= 16;
|
||||
continue;
|
||||
}
|
||||
/* write byte 0x80
|
||||
write LBA_to_CHS(partition_offset)
|
||||
write byte filesystem_type
|
||||
write LBA_to_CHS(image_size-1)
|
||||
write dword partition_offset
|
||||
write dword image_size
|
||||
*/
|
||||
lsb_to_buf(&wpt, 0x80, 8, 0);
|
||||
lba512chs_to_buf(&wpt, part_offset, head_count, sector_count);
|
||||
lsb_to_buf(&wpt, fs_type, 8, 0);
|
||||
lba512chs_to_buf(&wpt, hd_img_blocks - 1, head_count, sector_count);
|
||||
lsb_to_buf(&wpt, part_offset, 32, 0);
|
||||
if (hd_img_blocks - (off_t) part_offset > (off_t) 0xffffffff)
|
||||
nominal_part_size = 0xffffffff;
|
||||
else
|
||||
nominal_part_size = hd_img_blocks - (off_t) part_offset;
|
||||
lsb_to_buf(&wpt, nominal_part_size, 32, 0);
|
||||
}
|
||||
|
||||
/* write word 0xaa55 # Offset 510
|
||||
*/
|
||||
lsb_to_buf(&wpt, 0xaa55, 16, 0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
874
libisofs/md5.c
Normal file
874
libisofs/md5.c
Normal file
@ -0,0 +1,874 @@
|
||||
/*
|
||||
* 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "writer.h"
|
||||
#include "messages.h"
|
||||
#include "ecma119.h"
|
||||
#include "image.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
|
||||
/* This code is derived from RFC 1321 and implements computation of the
|
||||
"RSA Data Security, Inc. MD5 Message-Digest Algorithm" */
|
||||
|
||||
#define Libisofs_md5_S11 7
|
||||
#define Libisofs_md5_S12 12
|
||||
#define Libisofs_md5_S13 17
|
||||
#define Libisofs_md5_S14 22
|
||||
#define Libisofs_md5_S21 5
|
||||
#define Libisofs_md5_S22 9
|
||||
#define Libisofs_md5_S23 14
|
||||
#define Libisofs_md5_S24 20
|
||||
#define Libisofs_md5_S31 4
|
||||
#define Libisofs_md5_S32 11
|
||||
#define Libisofs_md5_S33 16
|
||||
#define Libisofs_md5_S34 23
|
||||
#define Libisofs_md5_S41 6
|
||||
#define Libisofs_md5_S42 10
|
||||
#define Libisofs_md5_S43 15
|
||||
#define Libisofs_md5_S44 21
|
||||
|
||||
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
#define Libisofs_md5_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define Libisofs_md5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define Libisofs_md5_H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define Libisofs_md5_I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
#define Libisofs_md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation.
|
||||
*/
|
||||
#define Libisofs_md5_FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += Libisofs_md5_F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define Libisofs_md5_GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += Libisofs_md5_G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define Libisofs_md5_HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += Libisofs_md5_H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define Libisofs_md5_II(a, b, c, d, x, s, ac) { \
|
||||
(a) += Libisofs_md5_I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
|
||||
/* MD5 context. */
|
||||
struct _libisofs_md5_ctx {
|
||||
uint32_t state[4]; /* state (ABCD) */
|
||||
uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
};
|
||||
|
||||
typedef struct _libisofs_md5_ctx libisofs_md5_ctx;
|
||||
|
||||
|
||||
/* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static int md5__transform (uint32_t state[4], unsigned char block[64])
|
||||
{
|
||||
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < 64; i++, j += 4)
|
||||
x[i] = ((uint32_t)block[j]) | (((uint32_t)block[j+1]) << 8) |
|
||||
(((uint32_t)block[j+2]) << 16) | (((uint32_t)block[j+3]) << 24);
|
||||
|
||||
/* Round 1 */
|
||||
Libisofs_md5_FF (a, b, c, d, x[ 0], Libisofs_md5_S11, 0xd76aa478); /* 1 */
|
||||
Libisofs_md5_FF (d, a, b, c, x[ 1], Libisofs_md5_S12, 0xe8c7b756); /* 2 */
|
||||
Libisofs_md5_FF (c, d, a, b, x[ 2], Libisofs_md5_S13, 0x242070db); /* 3 */
|
||||
Libisofs_md5_FF (b, c, d, a, x[ 3], Libisofs_md5_S14, 0xc1bdceee); /* 4 */
|
||||
Libisofs_md5_FF (a, b, c, d, x[ 4], Libisofs_md5_S11, 0xf57c0faf); /* 5 */
|
||||
Libisofs_md5_FF (d, a, b, c, x[ 5], Libisofs_md5_S12, 0x4787c62a); /* 6 */
|
||||
Libisofs_md5_FF (c, d, a, b, x[ 6], Libisofs_md5_S13, 0xa8304613); /* 7 */
|
||||
Libisofs_md5_FF (b, c, d, a, x[ 7], Libisofs_md5_S14, 0xfd469501); /* 8 */
|
||||
Libisofs_md5_FF (a, b, c, d, x[ 8], Libisofs_md5_S11, 0x698098d8); /* 9 */
|
||||
Libisofs_md5_FF (d, a, b, c, x[ 9], Libisofs_md5_S12, 0x8b44f7af); /* 10 */
|
||||
Libisofs_md5_FF (c, d, a, b, x[10], Libisofs_md5_S13, 0xffff5bb1); /* 11 */
|
||||
Libisofs_md5_FF (b, c, d, a, x[11], Libisofs_md5_S14, 0x895cd7be); /* 12 */
|
||||
Libisofs_md5_FF (a, b, c, d, x[12], Libisofs_md5_S11, 0x6b901122); /* 13 */
|
||||
Libisofs_md5_FF (d, a, b, c, x[13], Libisofs_md5_S12, 0xfd987193); /* 14 */
|
||||
Libisofs_md5_FF (c, d, a, b, x[14], Libisofs_md5_S13, 0xa679438e); /* 15 */
|
||||
Libisofs_md5_FF (b, c, d, a, x[15], Libisofs_md5_S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
Libisofs_md5_GG (a, b, c, d, x[ 1], Libisofs_md5_S21, 0xf61e2562); /* 17 */
|
||||
Libisofs_md5_GG (d, a, b, c, x[ 6], Libisofs_md5_S22, 0xc040b340); /* 18 */
|
||||
Libisofs_md5_GG (c, d, a, b, x[11], Libisofs_md5_S23, 0x265e5a51); /* 19 */
|
||||
Libisofs_md5_GG (b, c, d, a, x[ 0], Libisofs_md5_S24, 0xe9b6c7aa); /* 20 */
|
||||
Libisofs_md5_GG (a, b, c, d, x[ 5], Libisofs_md5_S21, 0xd62f105d); /* 21 */
|
||||
Libisofs_md5_GG (d, a, b, c, x[10], Libisofs_md5_S22, 0x2441453); /* 22 */
|
||||
Libisofs_md5_GG (c, d, a, b, x[15], Libisofs_md5_S23, 0xd8a1e681); /* 23 */
|
||||
Libisofs_md5_GG (b, c, d, a, x[ 4], Libisofs_md5_S24, 0xe7d3fbc8); /* 24 */
|
||||
Libisofs_md5_GG (a, b, c, d, x[ 9], Libisofs_md5_S21, 0x21e1cde6); /* 25 */
|
||||
Libisofs_md5_GG (d, a, b, c, x[14], Libisofs_md5_S22, 0xc33707d6); /* 26 */
|
||||
Libisofs_md5_GG (c, d, a, b, x[ 3], Libisofs_md5_S23, 0xf4d50d87); /* 27 */
|
||||
Libisofs_md5_GG (b, c, d, a, x[ 8], Libisofs_md5_S24, 0x455a14ed); /* 28 */
|
||||
Libisofs_md5_GG (a, b, c, d, x[13], Libisofs_md5_S21, 0xa9e3e905); /* 29 */
|
||||
Libisofs_md5_GG (d, a, b, c, x[ 2], Libisofs_md5_S22, 0xfcefa3f8); /* 30 */
|
||||
Libisofs_md5_GG (c, d, a, b, x[ 7], Libisofs_md5_S23, 0x676f02d9); /* 31 */
|
||||
Libisofs_md5_GG (b, c, d, a, x[12], Libisofs_md5_S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
Libisofs_md5_HH (a, b, c, d, x[ 5], Libisofs_md5_S31, 0xfffa3942); /* 33 */
|
||||
Libisofs_md5_HH (d, a, b, c, x[ 8], Libisofs_md5_S32, 0x8771f681); /* 34 */
|
||||
Libisofs_md5_HH (c, d, a, b, x[11], Libisofs_md5_S33, 0x6d9d6122); /* 35 */
|
||||
Libisofs_md5_HH (b, c, d, a, x[14], Libisofs_md5_S34, 0xfde5380c); /* 36 */
|
||||
Libisofs_md5_HH (a, b, c, d, x[ 1], Libisofs_md5_S31, 0xa4beea44); /* 37 */
|
||||
Libisofs_md5_HH (d, a, b, c, x[ 4], Libisofs_md5_S32, 0x4bdecfa9); /* 38 */
|
||||
Libisofs_md5_HH (c, d, a, b, x[ 7], Libisofs_md5_S33, 0xf6bb4b60); /* 39 */
|
||||
Libisofs_md5_HH (b, c, d, a, x[10], Libisofs_md5_S34, 0xbebfbc70); /* 40 */
|
||||
Libisofs_md5_HH (a, b, c, d, x[13], Libisofs_md5_S31, 0x289b7ec6); /* 41 */
|
||||
Libisofs_md5_HH (d, a, b, c, x[ 0], Libisofs_md5_S32, 0xeaa127fa); /* 42 */
|
||||
Libisofs_md5_HH (c, d, a, b, x[ 3], Libisofs_md5_S33, 0xd4ef3085); /* 43 */
|
||||
Libisofs_md5_HH (b, c, d, a, x[ 6], Libisofs_md5_S34, 0x4881d05); /* 44 */
|
||||
Libisofs_md5_HH (a, b, c, d, x[ 9], Libisofs_md5_S31, 0xd9d4d039); /* 45 */
|
||||
Libisofs_md5_HH (d, a, b, c, x[12], Libisofs_md5_S32, 0xe6db99e5); /* 46 */
|
||||
Libisofs_md5_HH (c, d, a, b, x[15], Libisofs_md5_S33, 0x1fa27cf8); /* 47 */
|
||||
Libisofs_md5_HH (b, c, d, a, x[ 2], Libisofs_md5_S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
Libisofs_md5_II (a, b, c, d, x[ 0], Libisofs_md5_S41, 0xf4292244); /* 49 */
|
||||
Libisofs_md5_II (d, a, b, c, x[ 7], Libisofs_md5_S42, 0x432aff97); /* 50 */
|
||||
Libisofs_md5_II (c, d, a, b, x[14], Libisofs_md5_S43, 0xab9423a7); /* 51 */
|
||||
Libisofs_md5_II (b, c, d, a, x[ 5], Libisofs_md5_S44, 0xfc93a039); /* 52 */
|
||||
Libisofs_md5_II (a, b, c, d, x[12], Libisofs_md5_S41, 0x655b59c3); /* 53 */
|
||||
Libisofs_md5_II (d, a, b, c, x[ 3], Libisofs_md5_S42, 0x8f0ccc92); /* 54 */
|
||||
Libisofs_md5_II (c, d, a, b, x[10], Libisofs_md5_S43, 0xffeff47d); /* 55 */
|
||||
Libisofs_md5_II (b, c, d, a, x[ 1], Libisofs_md5_S44, 0x85845dd1); /* 56 */
|
||||
Libisofs_md5_II (a, b, c, d, x[ 8], Libisofs_md5_S41, 0x6fa87e4f); /* 57 */
|
||||
Libisofs_md5_II (d, a, b, c, x[15], Libisofs_md5_S42, 0xfe2ce6e0); /* 58 */
|
||||
Libisofs_md5_II (c, d, a, b, x[ 6], Libisofs_md5_S43, 0xa3014314); /* 59 */
|
||||
Libisofs_md5_II (b, c, d, a, x[13], Libisofs_md5_S44, 0x4e0811a1); /* 60 */
|
||||
Libisofs_md5_II (a, b, c, d, x[ 4], Libisofs_md5_S41, 0xf7537e82); /* 61 */
|
||||
Libisofs_md5_II (d, a, b, c, x[11], Libisofs_md5_S42, 0xbd3af235); /* 62 */
|
||||
Libisofs_md5_II (c, d, a, b, x[ 2], Libisofs_md5_S43, 0x2ad7d2bb); /* 63 */
|
||||
Libisofs_md5_II (b, c, d, a, x[ 9], Libisofs_md5_S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
/* Zeroize sensitive information. */
|
||||
memset ((char *) x, 0, sizeof (x));
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int md5__encode(unsigned char *output, uint32_t *input,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int md5_init(libisofs_md5_ctx *ctx, int flag)
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
/* Load magic initialization constants. */
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xefcdab89;
|
||||
ctx->state[2] = 0x98badcfe;
|
||||
ctx->state[3] = 0x10325476;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* MD5 block update operation. Continues an MD5 message-digest
|
||||
operation, processing another message block, and updating the
|
||||
context.
|
||||
*/
|
||||
static int md5_update(libisofs_md5_ctx *ctx, unsigned char *data,
|
||||
int datalen, int flag)
|
||||
{
|
||||
int i, index, partlen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = ((ctx->count[0] >> 3) & 0x3F);
|
||||
/* Update number of bits */
|
||||
if ((ctx->count[0] += ((uint32_t) datalen << 3)) <
|
||||
((uint32_t) datalen << 3))
|
||||
ctx->count[1]++;
|
||||
ctx->count[1] += ((uint32_t) datalen >> 29);
|
||||
partlen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible. */
|
||||
if (datalen >= partlen) {
|
||||
memcpy((char *) &ctx->buffer[index], (char *) data, partlen);
|
||||
md5__transform(ctx->state, ctx->buffer);
|
||||
for (i = partlen; i + 63 < datalen; i += 64)
|
||||
md5__transform(ctx->state, &data[i]);
|
||||
index = 0;
|
||||
} else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining data */
|
||||
memcpy((char *) &ctx->buffer[index], (char *) &data[i],datalen-i);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int md5_final(libisofs_md5_ctx *ctx, char result[16], int flag)
|
||||
{
|
||||
unsigned char bits[8], *respt;
|
||||
unsigned int index, padlen;
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* Save number of bits */
|
||||
md5__encode(bits, ctx->count, 8);
|
||||
/* Pad out to 56 mod 64. */
|
||||
index = (unsigned int)((ctx->count[0] >> 3) & 0x3f);
|
||||
padlen = (index < 56) ? (56 - index) : (120 - index);
|
||||
md5_update(ctx, PADDING, padlen,0);
|
||||
/* Append length (before padding) */
|
||||
md5_update(ctx, bits, 8,0);
|
||||
/* Store state in result */
|
||||
respt= (unsigned char *) result;
|
||||
md5__encode(respt, ctx->state, 16);
|
||||
/* Zeroize sensitive information. */
|
||||
memset ((char *) ctx, 0, sizeof (*ctx));
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** Compute a MD5 checksum from one or more calls of this function.
|
||||
The first call has to be made with flag bit0 == 1. It may already submit
|
||||
processing payload in data and datalen.
|
||||
The last call has to be made with bit15 set. Normally bit1 will be set
|
||||
too in order to receive the checksum before it gets disposed.
|
||||
bit1 may only be set in the last call or together with bit2.
|
||||
The combination of bit1 and bit2 may be used to get an intermediate
|
||||
result without hampering an ongoing checksum computation.
|
||||
|
||||
@param ctx the checksum context which stores the state between calls.
|
||||
It gets created with flag bit0 and disposed with bit15.
|
||||
With flag bit0, *ctx has to be NULL or point to freeable
|
||||
memory.
|
||||
@param data the bytes to be checksummed
|
||||
@param datalen the number of bytes in data
|
||||
@param result returns the 16 bytes of checksum if called with bit1 set
|
||||
@param flag bit0= allocate and init *ctx
|
||||
bit1= transfer ctx to result
|
||||
bit2= with bit 0 : clone new *ctx from data
|
||||
bit15= free *ctx
|
||||
*/
|
||||
static
|
||||
int libisofs_md5(void **ctx_in, char *data, int datalen,
|
||||
char result[16], int flag)
|
||||
/* *ctx has to be NULL or point to freeable memory */
|
||||
/*
|
||||
bit0= allocate and init *ctx
|
||||
bit1= transfer ctx to result
|
||||
bit2= with bit 0 : clone new *ctx from data
|
||||
bit15= free *ctx
|
||||
*/
|
||||
{
|
||||
unsigned char *datapt;
|
||||
libisofs_md5_ctx **ctx;
|
||||
|
||||
ctx= (libisofs_md5_ctx **) ctx_in;
|
||||
if(flag&1) {
|
||||
if(*ctx!=NULL)
|
||||
free((char *) *ctx);
|
||||
*ctx= calloc(1, sizeof(libisofs_md5_ctx));
|
||||
if(*ctx==NULL)
|
||||
return(-1);
|
||||
md5_init(*ctx,0);
|
||||
if(flag&4)
|
||||
memcpy((char *) *ctx,data,sizeof(libisofs_md5_ctx));
|
||||
}
|
||||
if(*ctx==NULL)
|
||||
return(0);
|
||||
if(datalen>0) {
|
||||
datapt= (unsigned char *) data;
|
||||
md5_update(*ctx, datapt, datalen, 0);
|
||||
}
|
||||
if(flag&2)
|
||||
md5_final(*ctx, result, 0);
|
||||
if(flag&(1<<15)) {
|
||||
free((char *) *ctx);
|
||||
*ctx= NULL;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/* Public MD5 computing facility */
|
||||
|
||||
/* API */
|
||||
int iso_md5_start(void **md5_context)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libisofs_md5(md5_context, NULL, 0, NULL, 1);
|
||||
if (ret <= 0)
|
||||
return ISO_OUT_OF_MEM;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* API */
|
||||
int iso_md5_compute(void *md5_context, char *data, int datalen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libisofs_md5(&md5_context, data, datalen, NULL, 0);
|
||||
if (ret <= 0)
|
||||
return ISO_NULL_POINTER;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* API */
|
||||
int iso_md5_clone(void *old_md5_context, void **new_md5_context)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libisofs_md5(new_md5_context, old_md5_context, 0, NULL, 1 | 4);
|
||||
if (ret < 0)
|
||||
return ISO_OUT_OF_MEM;
|
||||
if (ret == 0)
|
||||
return ISO_NULL_POINTER;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* API */
|
||||
int iso_md5_end(void **md5_context, char result[16])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libisofs_md5(md5_context, NULL, 0, result, 2 | (1 << 15));
|
||||
if (ret <= 0)
|
||||
return ISO_NULL_POINTER;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* API */
|
||||
int iso_md5_match(char first_md5[16], char second_md5[16])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i= 0; i < 16; i++)
|
||||
if (first_md5[i] != second_md5[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/* Function to identify and manage md5sum indice of the old image.
|
||||
* data is supposed to be a 4 byte integer, bit 31 shall be 0,
|
||||
* value 0 of this integer means that it is not a valid index.
|
||||
*/
|
||||
int checksum_cx_xinfo_func(void *data, int flag)
|
||||
{
|
||||
/* data is an int disguised as pointer. It does not point to memory. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The iso_node_xinfo_cloner function which gets associated to
|
||||
* checksum_cx_xinfo_func by iso_init() resp. iso_init_with_flag() via
|
||||
* iso_node_xinfo_make_clonable()
|
||||
*/
|
||||
int checksum_cx_xinfo_cloner(void *old_data, void **new_data, int flag)
|
||||
{
|
||||
*new_data = NULL;
|
||||
if (flag)
|
||||
return ISO_XINFO_NO_CLONE;
|
||||
if (old_data == NULL)
|
||||
return 0;
|
||||
/* data is an int disguised as pointer. It does not point to memory. */
|
||||
*new_data = old_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Function to identify and manage md5 sums of unspecified providence stored
|
||||
* directly in this xinfo.
|
||||
*/
|
||||
int checksum_md5_xinfo_func(void *data, int flag)
|
||||
{
|
||||
if (data == NULL)
|
||||
return 1;
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The iso_node_xinfo_cloner function which gets associated to
|
||||
* checksum_md5_xinfo_func by iso_init() resp. iso_init_with_flag() via
|
||||
* iso_node_xinfo_make_clonable()
|
||||
*/
|
||||
int checksum_md5_xinfo_cloner(void *old_data, void **new_data, int flag)
|
||||
{
|
||||
*new_data = NULL;
|
||||
if (flag)
|
||||
return ISO_XINFO_NO_CLONE;
|
||||
if (old_data == NULL)
|
||||
return 0;
|
||||
*new_data = calloc(1, 16);
|
||||
if (*new_data == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
memcpy(*new_data, old_data, 16);
|
||||
return 16;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/* MD5 checksum image writer */
|
||||
|
||||
/*
|
||||
@flag bit0= recursion
|
||||
bit1= session will be appended to an existing image
|
||||
*/
|
||||
static
|
||||
int checksum_copy_old_nodes(Ecma119Image *target, IsoNode *node, int flag)
|
||||
{
|
||||
IsoNode *pos;
|
||||
IsoFile *file;
|
||||
IsoImage *img;
|
||||
int ret, i;
|
||||
size_t value_length;
|
||||
unsigned int idx = 0, old_idx = 0;
|
||||
char *value = NULL, *md5_pt = NULL;
|
||||
void *xipt;
|
||||
|
||||
img = target->image;
|
||||
if (target->checksum_buffer == NULL)
|
||||
return 0;
|
||||
|
||||
if (node->type == LIBISO_FILE) {
|
||||
file = (IsoFile *) node;
|
||||
if (file->from_old_session && target->appendable) {
|
||||
/* Look for checksums at various places */
|
||||
|
||||
/* Try checksum directly stored with node */
|
||||
if (md5_pt == NULL) {
|
||||
ret = iso_node_get_xinfo(node, checksum_md5_xinfo_func, &xipt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 1)
|
||||
md5_pt = (char *) xipt;
|
||||
}
|
||||
|
||||
/* Try checksum index to image checksum buffer */
|
||||
if (md5_pt == NULL && img->checksum_array != NULL) {
|
||||
ret = iso_node_get_xinfo(node, checksum_cx_xinfo_func, &xipt);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
/* xipt is an int disguised as void pointer */
|
||||
old_idx = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
old_idx = (old_idx << 8) | ((unsigned char *) &xipt)[i];
|
||||
|
||||
if (old_idx == 0 || old_idx > img->checksum_idx_count - 1)
|
||||
return 0;
|
||||
md5_pt = img->checksum_array + 16 * old_idx;
|
||||
}
|
||||
|
||||
if (md5_pt == NULL)
|
||||
return 0;
|
||||
|
||||
ret = iso_node_lookup_attr(node, "isofs.cx", &value_length,
|
||||
&value, 0);
|
||||
if (ret == 1 && value_length == 4) {
|
||||
for (i = 0; i < 4; i++)
|
||||
idx = (idx << 8) | ((unsigned char *) value)[i];
|
||||
if (idx > 0 && idx <= target->checksum_idx_counter) {
|
||||
memcpy(target->checksum_buffer + 16 * idx, md5_pt, 16);
|
||||
}
|
||||
}
|
||||
if (value != NULL)
|
||||
free(value);
|
||||
iso_node_remove_xinfo(node, checksum_md5_xinfo_func);
|
||||
iso_node_remove_xinfo(node, checksum_cx_xinfo_func);
|
||||
}
|
||||
} else if (node->type == LIBISO_DIR) {
|
||||
for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) {
|
||||
ret = checksum_copy_old_nodes(target, pos, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int checksum_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
{
|
||||
size_t size;
|
||||
Ecma119Image *t;
|
||||
int ret;
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
t = writer->target;
|
||||
|
||||
t->checksum_array_pos = t->curblock;
|
||||
/* (t->curblock already contains t->ms_block) */
|
||||
t->checksum_range_start = t->ms_block;
|
||||
size = (t->checksum_idx_counter + 2) / 128;
|
||||
if (size * 128 < t->checksum_idx_counter + 2)
|
||||
size++;
|
||||
t->curblock += size;
|
||||
t->checksum_range_size = t->checksum_array_pos + size
|
||||
- t->checksum_range_start;
|
||||
|
||||
/* Extra block for stream detectable checksum tag */
|
||||
t->checksum_tag_pos = t->curblock;
|
||||
t->curblock++;
|
||||
|
||||
/* Allocate array of MD5 sums */
|
||||
t->checksum_buffer = calloc(size, 2048);
|
||||
if (t->checksum_buffer == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
|
||||
/* Copy MD5 from nodes of old image into writer->data */
|
||||
ret = checksum_copy_old_nodes(t, (IsoNode *) t->image->root, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Record lba,count,size,cecksum_type in "isofs.ca" of root node */
|
||||
ret = iso_root_set_isofsca((IsoNode *) t->image->root,
|
||||
t->checksum_range_start,
|
||||
t->checksum_array_pos,
|
||||
t->checksum_idx_counter + 2, 16, "MD5", 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int checksum_writer_write_vol_desc(IsoImageWriter *writer)
|
||||
{
|
||||
|
||||
/* The superblock checksum tag has to be written after
|
||||
the Volume Descriptor Set Terminator and thus may not be
|
||||
written by this function. (It would have been neat, though).
|
||||
*/
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int checksum_writer_write_data(IsoImageWriter *writer)
|
||||
{
|
||||
int wres, res;
|
||||
size_t i, size;
|
||||
Ecma119Image *t;
|
||||
void *ctx = NULL;
|
||||
char md5[16];
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
t = writer->target;
|
||||
iso_msg_debug(t->image->id, "Writing Checksums...");
|
||||
|
||||
/* Write image checksum to index 0 */
|
||||
if (t->checksum_ctx != NULL) {
|
||||
res = iso_md5_clone(t->checksum_ctx, &ctx);
|
||||
if (res > 0) {
|
||||
res = iso_md5_end(&ctx, t->image_md5);
|
||||
if (res > 0)
|
||||
memcpy(t->checksum_buffer + 0 * 16, t->image_md5, 16);
|
||||
}
|
||||
}
|
||||
|
||||
size = (t->checksum_idx_counter + 2) / 128;
|
||||
if (size * 128 < t->checksum_idx_counter + 2)
|
||||
size++;
|
||||
|
||||
/* Write checksum of checksum array as index t->checksum_idx_counter + 1 */
|
||||
res = iso_md5_start(&ctx);
|
||||
if (res > 0) {
|
||||
for (i = 0; i < t->checksum_idx_counter + 1; i++)
|
||||
iso_md5_compute(ctx,
|
||||
t->checksum_buffer + ((size_t) i) * (size_t) 16, 16);
|
||||
res = iso_md5_end(&ctx, md5);
|
||||
if (res > 0)
|
||||
memcpy(t->checksum_buffer + (t->checksum_idx_counter + 1) * 16,
|
||||
md5, 16);
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
wres = iso_write(t, t->checksum_buffer + ((size_t) 2048) * i, 2048);
|
||||
if (wres < 0) {
|
||||
res = wres;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
if (t->checksum_ctx == NULL) {
|
||||
res = ISO_SUCCESS;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* Write stream detectable checksum tag to extra block */;
|
||||
res = iso_md5_write_tag(t, 1);
|
||||
if (res < 0)
|
||||
goto ex;
|
||||
|
||||
res = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (ctx != NULL)
|
||||
iso_md5_end(&ctx, md5);
|
||||
return(res);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int checksum_writer_free_data(IsoImageWriter *writer)
|
||||
{
|
||||
/* nothing was allocated at writer->data */
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int checksum_writer_create(Ecma119Image *target)
|
||||
{
|
||||
IsoImageWriter *writer;
|
||||
|
||||
writer = malloc(sizeof(IsoImageWriter));
|
||||
if (writer == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
writer->compute_data_blocks = checksum_writer_compute_data_blocks;
|
||||
writer->write_vol_desc = checksum_writer_write_vol_desc;
|
||||
writer->write_data = checksum_writer_write_data;
|
||||
writer->free_data = checksum_writer_free_data;
|
||||
writer->data = NULL;
|
||||
writer->target = target;
|
||||
|
||||
/* add this writer to image */
|
||||
target->writers[target->nwriters++] = writer;
|
||||
/* Account for superblock checksum tag */
|
||||
if (target->md5_session_checksum) {
|
||||
target->checksum_sb_tag_pos = target->curblock;
|
||||
target->curblock++;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int iso_md5_write_scdbackup_tag(Ecma119Image *t, char *tag_block, int flag)
|
||||
{
|
||||
void *ctx = NULL;
|
||||
off_t pos = 0, line_start;
|
||||
int record_len, block_len, ret, i;
|
||||
char postext[40], md5[16], *record = NULL;
|
||||
|
||||
LIBISO_ALLOC_MEM(record, char, 160);
|
||||
line_start = strlen(tag_block);
|
||||
iso_md5_compute(t->checksum_ctx, tag_block, line_start);
|
||||
ret = iso_md5_clone(t->checksum_ctx, &ctx);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
ret = iso_md5_end(&ctx, md5);
|
||||
|
||||
pos = (off_t) t->checksum_tag_pos * (off_t) 2048 + line_start;
|
||||
if(pos >= 1000000000)
|
||||
sprintf(postext, "%u%9.9u", (unsigned int) (pos / 1000000000),
|
||||
(unsigned int) (pos % 1000000000));
|
||||
else
|
||||
sprintf(postext, "%u", (unsigned int) pos);
|
||||
sprintf(record, "%s %s ", t->scdbackup_tag_parm, postext);
|
||||
record_len = strlen(record);
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(record + record_len + 2 * i,
|
||||
"%2.2x", ((unsigned char *) md5)[i]);
|
||||
record_len += 32;
|
||||
|
||||
ret = iso_md5_start(&ctx);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
iso_md5_compute(ctx, record, record_len);
|
||||
iso_md5_end(&ctx, md5);
|
||||
|
||||
sprintf(tag_block + line_start, "scdbackup_checksum_tag_v0.1 %s %d %s ",
|
||||
postext, record_len, record);
|
||||
block_len = strlen(tag_block);
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(tag_block + block_len + 2 * i,
|
||||
"%2.2x", ((unsigned char *) md5)[i]);
|
||||
block_len+= 32;
|
||||
tag_block[block_len++]= '\n';
|
||||
|
||||
if (t->scdbackup_tag_written != NULL)
|
||||
strncpy(t->scdbackup_tag_written, tag_block + line_start,
|
||||
block_len - line_start);
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (ctx != NULL)
|
||||
iso_md5_end(&ctx, md5);
|
||||
LIBISO_FREE_MEM(record);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Write stream detectable checksum tag to extra block.
|
||||
* @flag bit0-7= tag type
|
||||
* 1= session tag (End checksumming.)
|
||||
* 2= superblock tag (System Area and Volume Descriptors)
|
||||
* 3= tree tag (ECMA-119 and Rock Ridge tree)
|
||||
* 4= relocated superblock tag (at LBA 0 of overwriteable media)
|
||||
* Write to target->opts_overwrite rather than to iso_write().
|
||||
*/
|
||||
int iso_md5_write_tag(Ecma119Image *t, int flag)
|
||||
{
|
||||
int ret, mode, l, i, wres, tag_id_len;
|
||||
void *ctx = NULL;
|
||||
char md5[16], *tag_block = NULL, *tag_id;
|
||||
uint32_t size = 0, pos = 0, start;
|
||||
|
||||
LIBISO_ALLOC_MEM(tag_block, char, 2048);
|
||||
start = t->checksum_range_start;
|
||||
mode = flag & 255;
|
||||
if (mode < 1 || mode > 4)
|
||||
{ret = ISO_WRONG_ARG_VALUE; goto ex;}
|
||||
ret = iso_md5_clone(t->checksum_ctx, &ctx);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
ret = iso_md5_end(&ctx, md5);
|
||||
if (mode == 1) {
|
||||
size = t->checksum_range_size;
|
||||
pos = t->checksum_tag_pos;
|
||||
} else {
|
||||
if (mode == 2) {
|
||||
pos = t->checksum_sb_tag_pos;
|
||||
} else if (mode == 3) {
|
||||
pos = t->checksum_tree_tag_pos;
|
||||
} else if (mode == 4) {
|
||||
pos = t->checksum_rlsb_tag_pos;
|
||||
start = pos - (pos % 32);
|
||||
}
|
||||
size = pos - start;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
|
||||
iso_util_tag_magic(mode, &tag_id, &tag_id_len, 0);
|
||||
sprintf(tag_block, "%s pos=%u range_start=%u range_size=%u",
|
||||
tag_id, pos, start, size);
|
||||
|
||||
l = strlen(tag_block);
|
||||
if (mode == 2) {
|
||||
sprintf(tag_block + l, " next=%u", t->checksum_tree_tag_pos);
|
||||
} else if (mode == 3) {
|
||||
sprintf(tag_block + l, " next=%u", t->checksum_tag_pos);
|
||||
} else if (mode == 4) {
|
||||
sprintf(tag_block + l, " session_start=%u", t->ms_block);
|
||||
}
|
||||
strcat(tag_block + l, " md5=");
|
||||
l = strlen(tag_block);
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(tag_block + l + 2 * i, "%2.2x",
|
||||
((unsigned char *) md5)[i]);
|
||||
l+= 32;
|
||||
|
||||
ret = iso_md5_start(&ctx);
|
||||
if (ret > 0) {
|
||||
iso_md5_compute(ctx, tag_block, l);
|
||||
iso_md5_end(&ctx, md5);
|
||||
strcpy(tag_block + l, " self=");
|
||||
l += 6;
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(tag_block + l + 2 * i, "%2.2x",
|
||||
((unsigned char *) md5)[i]);
|
||||
}
|
||||
tag_block[l + 32] = '\n';
|
||||
|
||||
if (mode == 1 && t->scdbackup_tag_parm[0]) {
|
||||
if (t->ms_block > 0) {
|
||||
iso_msg_submit(t->image->id, ISO_SCDBACKUP_TAG_NOT_0, 0, NULL);
|
||||
} else {
|
||||
ret = iso_md5_write_scdbackup_tag(t, tag_block, 0);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == 4) {
|
||||
if (t->opts_overwrite != NULL)
|
||||
memcpy(t->opts_overwrite + pos * 2048, tag_block, 2048);
|
||||
} else {
|
||||
wres = iso_write(t, tag_block, 2048);
|
||||
if (wres < 0) {
|
||||
ret = wres;
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (ctx != NULL)
|
||||
iso_md5_end(&ctx, md5);
|
||||
LIBISO_FREE_MEM(tag_block);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
41
libisofs/md5.h
Normal file
41
libisofs/md5.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_MD5_H_
|
||||
#define LIBISO_MD5_H_
|
||||
|
||||
|
||||
/* The MD5 computation API is in libisofs.h : iso_md5_start() et.al. */
|
||||
|
||||
|
||||
/** Create a writer object for checksums and add it to the writer list of
|
||||
the given Ecma119Image.
|
||||
*/
|
||||
int checksum_writer_create(Ecma119Image *target);
|
||||
|
||||
|
||||
/* Write stream detectable checksum tag to extra block.
|
||||
* All tag ranges start at the beginning of the System Area (i.e. t->ms_block)
|
||||
* and stem from the same MD5 computation context. Tag types 2 and 3 are
|
||||
* intermediate checksums. Type 2 announces the existence of type 3.
|
||||
* If both match, then at least the directory tree is trustworthy.
|
||||
* Type 1 is written at the very end of the session. If it matches, then
|
||||
* the whole image is trustworthy.
|
||||
* @param t The image being written
|
||||
* @flag bit0-7= tag type
|
||||
* 1= session tag (End checksumming.)
|
||||
* 2= superblock tag (System Area and Volume Descriptors)
|
||||
* 3= tree tag (ECMA-119 and Rock Ridge tree)
|
||||
*/
|
||||
int iso_md5_write_tag(Ecma119Image *t, int flag);
|
||||
|
||||
|
||||
#endif /* ! LIBISO_MD5_H_ */
|
||||
|
||||
|
@ -1,22 +1,48 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2009 - 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef Xorriso_standalonE
|
||||
|
||||
#ifdef Xorriso_with_libjtE
|
||||
#include "../libjte/libjte.h"
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
#include <libjte/libjte.h>
|
||||
#endif
|
||||
|
||||
#endif /* ! Xorriso_standalonE */
|
||||
|
||||
#include "libiso_msgs.h"
|
||||
#include "libisofs.h"
|
||||
#include "messages.h"
|
||||
|
||||
/*
|
||||
#include "util.h"
|
||||
#include "node.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 +66,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,20 +80,153 @@ int abort_threshold = LIBISO_MSGS_SEV_FAILURE;
|
||||
|
||||
struct libiso_msgs *libiso_msgr = NULL;
|
||||
|
||||
int iso_init()
|
||||
|
||||
/* ------------- List of xinfo clone functions ----------- */
|
||||
|
||||
struct iso_xinfo_cloner_assoc {
|
||||
iso_node_xinfo_func proc;
|
||||
iso_node_xinfo_cloner cloner;
|
||||
struct iso_xinfo_cloner_assoc *next;
|
||||
};
|
||||
|
||||
struct iso_xinfo_cloner_assoc *iso_xinfo_cloner_list = NULL;
|
||||
|
||||
/* API */
|
||||
int iso_node_xinfo_make_clonable(iso_node_xinfo_func proc,
|
||||
iso_node_xinfo_cloner cloner, int flag)
|
||||
{
|
||||
struct iso_xinfo_cloner_assoc *assoc;
|
||||
|
||||
/* Look for existing assoc of proc */
|
||||
for (assoc = iso_xinfo_cloner_list; assoc != NULL; assoc = assoc->next)
|
||||
if (assoc->proc == proc)
|
||||
break;
|
||||
|
||||
if (assoc == NULL) {
|
||||
assoc = calloc(1, sizeof(struct iso_xinfo_cloner_assoc));
|
||||
if (assoc == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
assoc->proc = proc;
|
||||
assoc->next = iso_xinfo_cloner_list;
|
||||
iso_xinfo_cloner_list = assoc;
|
||||
}
|
||||
assoc->cloner = cloner;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/* API */
|
||||
int iso_node_xinfo_get_cloner(iso_node_xinfo_func proc,
|
||||
iso_node_xinfo_cloner *cloner, int flag)
|
||||
{
|
||||
struct iso_xinfo_cloner_assoc *assoc;
|
||||
|
||||
*cloner = NULL;
|
||||
for (assoc = iso_xinfo_cloner_list; assoc != NULL; assoc = assoc->next) {
|
||||
if (assoc->proc != proc)
|
||||
continue;
|
||||
*cloner = assoc->cloner;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int iso_node_xinfo_dispose_cloners(int flag)
|
||||
{
|
||||
struct iso_xinfo_cloner_assoc *assoc, *next;
|
||||
|
||||
for (assoc = iso_xinfo_cloner_list; assoc != NULL; assoc = next) {
|
||||
next = assoc->next;
|
||||
free((char *) assoc);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* ------------- End of xinfo clone functions list ----------- */
|
||||
|
||||
|
||||
/*
|
||||
@param flag bit0= do not set up locale by LC_* environment variables
|
||||
*/
|
||||
int iso_init_with_flag(int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
|
||||
/* Ugly compile time check for header version compatibility.
|
||||
If everthing matches, then it produces no C code. In case of mismatch,
|
||||
intentionally faulty C code will be inserted.
|
||||
*/
|
||||
/* The indendation is an advise of man gcc to help old compilers ignoring */
|
||||
#if iso_libjte_req_major > LIBJTE_VERSION_MAJOR
|
||||
#define Libisofs_libjte_dot_h_too_olD 1
|
||||
#endif
|
||||
#if iso_libjte_req_major == LIBJTE_VERSION_MAJOR && iso_libjte_req_minor > LIBJTE_VERSION_MINOR
|
||||
#define Libisofs_libjte_dot_h_too_olD 1
|
||||
#endif
|
||||
#if iso_libjte_req_minor == LIBJTE_VERSION_MINOR && iso_libjte_req_micro > LIBJTE_VERSION_MICRO
|
||||
#define Libisofs_libjte_dot_h_too_olD 1
|
||||
#endif
|
||||
|
||||
#ifdef Libisofs_libjte_dot_h_too_olD
|
||||
LIBJTE_MISCONFIGURATION = 0;
|
||||
INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libjte_dot_h_TOO_OLD__SEE_libisofs_dot_h_AND_messages_c = 0;
|
||||
LIBJTE_MISCONFIGURATION_ = 0;
|
||||
#endif
|
||||
|
||||
if (! libjte__is_compatible(LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
|
||||
LIBJTE_VERSION_MICRO, 0)) {
|
||||
fprintf(stderr,
|
||||
"\nlibisofs: libjte TOO OLD ! Need at least libjte-%d.%d.%d\n\n",
|
||||
LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
|
||||
LIBJTE_VERSION_MICRO);
|
||||
return ISO_FATAL_ERROR;
|
||||
}
|
||||
|
||||
#endif /* Libisofs_with_libjtE */
|
||||
|
||||
if (! (flag & 1)) {
|
||||
iso_init_locale(0);
|
||||
}
|
||||
if (libiso_msgr == NULL) {
|
||||
if (libiso_msgs_new(&libiso_msgr, 0) <= 0)
|
||||
return ISO_FATAL_ERROR;
|
||||
}
|
||||
libiso_msgs_set_severities(libiso_msgr, LIBISO_MSGS_SEV_NEVER,
|
||||
LIBISO_MSGS_SEV_FATAL, "libisofs: ", 0);
|
||||
|
||||
ret = iso_node_xinfo_make_clonable(aaip_xinfo_func, aaip_xinfo_cloner, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = iso_node_xinfo_make_clonable(checksum_cx_xinfo_func,
|
||||
checksum_cx_xinfo_cloner, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = iso_node_xinfo_make_clonable(checksum_md5_xinfo_func,
|
||||
checksum_md5_xinfo_cloner, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = iso_node_xinfo_make_clonable(zisofs_zf_xinfo_func,
|
||||
zisofs_zf_xinfo_cloner, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = iso_node_xinfo_make_clonable(iso_px_ino_xinfo_func,
|
||||
iso_px_ino_xinfo_cloner, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iso_init()
|
||||
{
|
||||
return iso_init_with_flag(0);
|
||||
}
|
||||
|
||||
void iso_finish()
|
||||
{
|
||||
libiso_msgs_destroy(&libiso_msgr, 0);
|
||||
iso_node_xinfo_dispose_cloners(0);
|
||||
}
|
||||
|
||||
int iso_set_abort_severity(char *severity)
|
||||
@ -77,7 +236,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;
|
||||
@ -86,136 +245,245 @@ int iso_set_abort_severity(char *severity)
|
||||
|
||||
void iso_msg_debug(int imgid, const char *fmt, ...)
|
||||
{
|
||||
char msg[MAX_MSG_LEN];
|
||||
char *msg = NULL;
|
||||
va_list ap;
|
||||
|
||||
LIBISO_ALLOC_MEM_VOID(msg, char, MAX_MSG_LEN);
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, MAX_MSG_LEN, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
libiso_msgs_submit(libiso_msgr, imgid, 0x00000002, LIBISO_MSGS_SEV_DEBUG,
|
||||
LIBISO_MSGS_PRIO_ZERO, msg, 0, 0);
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(msg);
|
||||
}
|
||||
|
||||
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_BOOT_IMAGE_OVERFLOW:
|
||||
return "Too many boot images added";
|
||||
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";
|
||||
case ISO_MD5_AREA_CORRUPTED:
|
||||
return "Checksum area or checksum tag appear corrupted";
|
||||
case ISO_MD5_TAG_MISMATCH:
|
||||
return "Checksum mismatch between checksum tag and data blocks";
|
||||
case ISO_SB_TREE_CORRUPTED:
|
||||
return "Checksum mismatch in System Area, Volume Descriptors, or directory tree";
|
||||
case ISO_MD5_TAG_UNEXPECTED:
|
||||
return "Unexpected checksum tag type encountered";
|
||||
case ISO_MD5_TAG_MISPLACED:
|
||||
return "Misplaced checksum tag type encountered";
|
||||
case ISO_MD5_TAG_OTHER_RANGE:
|
||||
return "Checksum tag with unexpected address range encountered";
|
||||
case ISO_MD5_STREAM_CHANGE:
|
||||
return "Detected file content changes while it was written into the image";
|
||||
case ISO_SCDBACKUP_TAG_NOT_0:
|
||||
return "Session does not start at LBA 0. scdbackup checksum tag not written.";
|
||||
case ISO_BOOT_NO_CATALOG:
|
||||
return "No boot catalog created yet";
|
||||
case ISO_OVWRT_MS_TOO_SMALL:
|
||||
return "Multi-session offset too small for overwrite buffer";
|
||||
case ISO_PART_OFFST_TOO_SMALL:
|
||||
return "Partition offset too small for first tree root.";
|
||||
case ISO_OVWRT_FIFO_TOO_SMALL:
|
||||
return "The ring buffer is too small for overwrite buffer";
|
||||
case ISO_LIBJTE_NOT_ENABLED:
|
||||
return "Use of libjte was not enabled at compile time";
|
||||
case ISO_LIBJTE_START_FAILED:
|
||||
return "Failed to start up Jigdo Template Extraction";
|
||||
case ISO_LIBJTE_END_FAILED:
|
||||
return "Failed to finish Jigdo Template Extraction";
|
||||
case ISO_LIBJTE_FILE_FAILED:
|
||||
return "Failed to process file for Jigdo Template Extraction";
|
||||
case ISO_BOOT_TOO_MANY_MIPS:
|
||||
return "Too many MIPS Big Endian boot files given (max. 15)";
|
||||
case ISO_BOOT_FILE_MISSING:
|
||||
return "Boot file missing in image";
|
||||
case ISO_BAD_PARTITION_NO:
|
||||
return "Partition number out of range";
|
||||
case ISO_BAD_PARTITION_FILE:
|
||||
return "Cannot open data file for appended partition";
|
||||
case ISO_NON_MBR_SYS_AREA:
|
||||
return "May not combine appended partition with non-MBR system area";
|
||||
case ISO_DISPLACE_ROLLOVER:
|
||||
return "Displacement offset leads outside 32 bit range";
|
||||
case ISO_NAME_NEEDS_TRANSL:
|
||||
return "File name cannot be written into ECMA-119 untranslated";
|
||||
case ISO_STREAM_NO_CLONE:
|
||||
return "Data file input stream object offers no cloning method";
|
||||
case ISO_XINFO_NO_CLONE:
|
||||
return "Extended information class offers no cloning method";
|
||||
case ISO_MD5_TAG_COPIED:
|
||||
return "Found copied superblock checksum tag";
|
||||
case ISO_RR_NAME_TOO_LONG:
|
||||
return "Rock Ridge leaf name too long";
|
||||
case ISO_RR_NAME_RESERVED:
|
||||
return "Reserved Rock Ridge leaf name";
|
||||
case ISO_RR_PATH_TOO_LONG:
|
||||
return "Rock Ridge path too long";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
int iso_msg_is_abort(int errcode)
|
||||
{
|
||||
if (ISO_ERR_SEV(errcode) >= abort_threshold)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
if (errcode == (int) ISO_CANCELED && fmt == NULL) {
|
||||
return ISO_CANCELED;
|
||||
}
|
||||
|
||||
@ -227,30 +495,30 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (ISO_ERR_SEV(errcode) >= abort_threshold) {
|
||||
if (iso_msg_is_abort(errcode)) {
|
||||
return ISO_CANCELED;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 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 +527,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 +545,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 +573,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 +587,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 +603,60 @@ int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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 +678,42 @@ int iso_error_get_code(int e)
|
||||
{
|
||||
return ISO_ERR_CODE(e);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
int iso_libjte_forward_msgs(void *libjte_handle,
|
||||
int imgid, int errcode, int flag)
|
||||
{
|
||||
|
||||
#ifdef Libisofs_with_libjtE
|
||||
|
||||
char *msg = NULL;
|
||||
int res;
|
||||
struct libjte_env *handle = (struct libjte_env *) libjte_handle;
|
||||
|
||||
res = ISO_SUCCESS;
|
||||
while(1) {
|
||||
msg= libjte_get_next_message(handle);
|
||||
if(msg == NULL)
|
||||
break;
|
||||
res = iso_msg_submit(imgid, errcode, 0, msg);
|
||||
free(msg);
|
||||
}
|
||||
return res;
|
||||
|
||||
#else /* Libisofs_with_libjtE */
|
||||
|
||||
return ISO_SUCCESS;
|
||||
|
||||
#endif /* ! Libisofs_with_libjtE */
|
||||
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -24,6 +25,13 @@ extern int iso_message_id;
|
||||
*/
|
||||
void iso_msg_debug(int imgid, const char *fmt, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Inquire whether the given error code triggers the abort threshold
|
||||
*/
|
||||
int iso_msg_is_abort(int errcode);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param errcode
|
||||
@ -33,8 +41,22 @@ void iso_msg_debug(int imgid, const char *fmt, ...);
|
||||
* < 0 will be returned in any case. Use 0 if there is no previous
|
||||
* cause for the error.
|
||||
* @return
|
||||
* 1 on success, < 0 if function must abort asap.
|
||||
* 0 on success, < 0 if function must abort asap.
|
||||
*/
|
||||
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...);
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
/* Drains the libjte message list and puts out the messages via
|
||||
iso_msg_submit()
|
||||
*/
|
||||
int iso_libjte_forward_msgs(void *libjte_handle,
|
||||
int imgid, int errcode, int flag);
|
||||
|
||||
#endif /*MESSAGES_H_*/
|
||||
|
2363
libisofs/node.c
2363
libisofs/node.c
File diff suppressed because it is too large
Load Diff
363
libisofs/node.h
363
libisofs/node.h
@ -1,9 +1,11 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2009 - 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_NODE_H_
|
||||
#define LIBISO_NODE_H_
|
||||
@ -18,19 +20,47 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* #define LIBISO_EXTENDED_INFORMATION */
|
||||
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Maximum length of a leaf name in the libisofs node tree. This is currently
|
||||
restricted by the implemented maximum length of a Rock Ridge name.
|
||||
This might later become larger and may then be limited to smaller values.
|
||||
|
||||
Rock Ridge specs do not impose an explicit limit on name length.
|
||||
But 255 is also specified by
|
||||
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html
|
||||
which says
|
||||
NAME_MAX >= _XOPEN_NAME_MAX = 255
|
||||
*/
|
||||
#define LIBISOFS_NODE_NAME_MAX 255
|
||||
|
||||
|
||||
/* Maximum length of a path in the libisofs node tree.
|
||||
Rock Ridge specs do not impose an explicit limit on path length.
|
||||
|
||||
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html
|
||||
says
|
||||
PATH_MAX >= _XOPEN_PATH_MAX = 1024
|
||||
*/
|
||||
#define LIBISOFS_NODE_PATH_MAX 1024
|
||||
|
||||
|
||||
/**
|
||||
* The extended information is a way to attach additional information to each
|
||||
* IsoNode. External applications may want to use this extension system to
|
||||
* store application speficic information related to each node. On the other
|
||||
* IsoNode. External applications may want to use this extension system to
|
||||
* store application specific 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 +70,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
|
||||
* Initialized 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
|
||||
* 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 +130,10 @@ struct Iso_Node
|
||||
*/
|
||||
IsoNode *next;
|
||||
|
||||
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||
/**
|
||||
* Extended information for the node.
|
||||
*/
|
||||
IsoExtendedInfo *xinfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Iso_Dir
|
||||
@ -118,21 +144,19 @@ struct Iso_Dir
|
||||
IsoNode *children; /**< list of children. ptr to first child */
|
||||
};
|
||||
|
||||
/* IMPORTANT: Any change must be reflected by iso_tree_clone_file. */
|
||||
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 +164,48 @@ struct Iso_Symlink
|
||||
IsoNode node;
|
||||
|
||||
char *dest;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
struct Iso_Special
|
||||
{
|
||||
IsoNode node;
|
||||
dev_t dev;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
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 +213,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 +257,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 +278,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,20 +302,20 @@ 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
|
||||
* 1 if yes, <0 if not. The value is a specific ISO_* error code.
|
||||
*/
|
||||
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 +323,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 +335,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 +350,190 @@ 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);
|
||||
|
||||
|
||||
/**
|
||||
* Set the checksum index (typically comming from IsoFileSrc.checksum_index)
|
||||
* of a regular file node. The index is encoded as xattr "isofs.cx" with
|
||||
* four bytes of value.
|
||||
*/
|
||||
int iso_file_set_isofscx(IsoFile *file, unsigned int checksum_index,
|
||||
int flag);
|
||||
|
||||
|
||||
/**
|
||||
* Set the checksum area description. node should be the root node.
|
||||
* It is encoded as xattr "isofs.ca".
|
||||
*/
|
||||
int iso_root_set_isofsca(IsoNode *node, uint32_t start_lba, uint32_t end_lba,
|
||||
uint32_t count, uint32_t size, char *typetext,
|
||||
int flag);
|
||||
|
||||
/**
|
||||
* Get the checksum area description. node should be the root node.
|
||||
* It is encoded as xattr "isofs.ca".
|
||||
*/
|
||||
int iso_root_get_isofsca(IsoNode *node, uint32_t *start_lba, uint32_t *end_lba,
|
||||
uint32_t *count, uint32_t *size, char typetext[81],
|
||||
int flag);
|
||||
|
||||
|
||||
/**
|
||||
* Copy the xinfo list from one node to the another.
|
||||
*/
|
||||
int iso_node_clone_xinfo(IsoNode *from_node, IsoNode *to_node, int flag);
|
||||
|
||||
|
||||
/**
|
||||
* The iso_node_xinfo_func instance which governs the storing of the inode
|
||||
* number from Rock Ridge field PX.
|
||||
*/
|
||||
int iso_px_ino_xinfo_func(void *data, int flag);
|
||||
|
||||
/* The iso_node_xinfo_cloner function which gets associated to
|
||||
* iso_px_ino_xinfo_func by iso_init() resp. iso_init_with_flag() via
|
||||
* iso_node_xinfo_make_clonable()
|
||||
*/
|
||||
int iso_px_ino_xinfo_cloner(void *old_data, void **new_data, int flag);
|
||||
|
||||
|
||||
/* Function to identify and manage ZF parameters of zisofs compression.
|
||||
* data is supposed to be a pointer to struct zisofs_zf_info
|
||||
*/
|
||||
int zisofs_zf_xinfo_func(void *data, int flag);
|
||||
|
||||
/* The iso_node_xinfo_cloner function which gets associated to
|
||||
* zisofs_zf_xinfo_func by iso_init() resp. iso_init_with_flag() via
|
||||
* iso_node_xinfo_make_clonable()
|
||||
*/
|
||||
int zisofs_zf_xinfo_cloner(void *old_data, void **new_data, int flag);
|
||||
|
||||
|
||||
#endif /*LIBISO_NODE_H_*/
|
||||
|
1092
libisofs/rockridge.c
1092
libisofs/rockridge.c
File diff suppressed because it is too large
Load Diff
@ -1,26 +1,39 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 +41,7 @@
|
||||
|
||||
#include "ecma119.h"
|
||||
|
||||
|
||||
#define SUSP_SIG(entry, a, b) ((entry->sig[0] == a) && (entry->sig[1] == b))
|
||||
|
||||
/**
|
||||
@ -115,6 +129,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 +169,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 +264,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 +305,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,16 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "ecma119.h"
|
||||
#include "util.h"
|
||||
@ -75,8 +81,7 @@ int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue)
|
||||
* (IEEE 1281, SUSP. section 4)
|
||||
*/
|
||||
if (iter->ce_len) {
|
||||
uint32_t block;
|
||||
int nblocks;
|
||||
uint32_t block, nblocks;
|
||||
|
||||
/* A CE has found, there is another continuation area */
|
||||
nblocks = DIV_UP(iter->ce_off + iter->ce_len, BLOCK_SIZE);
|
||||
@ -168,11 +173,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,7 +306,7 @@ int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont)
|
||||
*name = realloc(*name, strlen(*name) + nm->len_sue[0] - 5 + 1);
|
||||
strncat(*name, (char*)nm->data.NM.name, nm->len_sue[0] - 5);
|
||||
} else {
|
||||
*name = strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
|
||||
*name = iso_util_strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
|
||||
}
|
||||
if (*name == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
@ -376,7 +384,7 @@ int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
|
||||
/* we don't have to add the '/' */
|
||||
strncat(*dest, comp, len);
|
||||
} else {
|
||||
*dest = strcopy(comp, len);
|
||||
*dest = iso_util_strcopy(comp, len);
|
||||
}
|
||||
if (*dest == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
@ -402,6 +410,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 +423,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 obsolete 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 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,31 +1,37 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2009 - 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "stream.h"
|
||||
#include "fsource.h"
|
||||
#include "util.h"
|
||||
#include "node.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX Libisofs_default_path_maX
|
||||
#endif
|
||||
|
||||
|
||||
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 +120,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 +129,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 +138,96 @@ 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;
|
||||
}
|
||||
|
||||
static
|
||||
IsoStream *fsrc_get_input_stream(IsoStream *stream, int flag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int fsrc_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iso_stream_cmp_ino(s1, s2, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fsrc_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||
int flag)
|
||||
{
|
||||
FSrcStreamData *data, *new_data;
|
||||
IsoStream *stream;
|
||||
int ret;
|
||||
|
||||
if (flag)
|
||||
return ISO_STREAM_NO_CLONE; /* unknown option required */
|
||||
|
||||
data = (FSrcStreamData*) old_stream->data;
|
||||
if (data->src->class->version < 2)
|
||||
return ISO_STREAM_NO_CLONE; /* No clone_src() method available */
|
||||
|
||||
*new_stream = NULL;
|
||||
stream = calloc(1, sizeof(IsoStream));
|
||||
if (stream == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
new_data = calloc(1, sizeof(FSrcStreamData));
|
||||
if (new_data == NULL) {
|
||||
free((char *) stream);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
*new_stream = stream;
|
||||
stream->class = old_stream->class;
|
||||
stream->refcount = 1;
|
||||
stream->data = new_data;
|
||||
|
||||
ret = data->src->class->clone_src(data->src, &(new_data->src), 0);
|
||||
if (ret < 0) {
|
||||
free((char *) stream);
|
||||
free((char *) new_data);
|
||||
return ret;
|
||||
}
|
||||
new_data->dev_id = data->dev_id;
|
||||
new_data->ino_id = data->ino_id;
|
||||
new_data->size = data->size;
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
IsoStreamIface fsrc_stream_class = {
|
||||
4, /* version */
|
||||
"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,
|
||||
fsrc_get_input_stream,
|
||||
fsrc_cmp_ino,
|
||||
fsrc_clone_stream
|
||||
};
|
||||
|
||||
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||
@ -169,7 +248,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 +260,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 +268,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 +277,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 +298,290 @@ 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((size_t) (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);
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_update_size(IsoStream *stream)
|
||||
{
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
IsoStream* cut_out_get_input_stream(IsoStream *stream, int flag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iso_stream_cmp_ino(s1, s2, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||
int flag)
|
||||
{
|
||||
struct cut_out_stream *data, *new_data;
|
||||
IsoStream *stream;
|
||||
int ret;
|
||||
|
||||
if (flag)
|
||||
return ISO_STREAM_NO_CLONE; /* unknown option required */
|
||||
|
||||
data = (struct cut_out_stream *) old_stream->data;
|
||||
if (data->src->class->version < 2)
|
||||
return ISO_STREAM_NO_CLONE; /* No clone_src() method available */
|
||||
|
||||
*new_stream = NULL;
|
||||
stream = calloc(1, sizeof(IsoStream));
|
||||
if (stream == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
stream->refcount = 1;
|
||||
stream->class = old_stream->class;
|
||||
new_data = calloc(1, sizeof(struct cut_out_stream));
|
||||
if (new_data == NULL) {
|
||||
free((char *) stream);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
ret = data->src->class->clone_src(data->src, &(new_data->src), 0);
|
||||
if (ret < 0) {
|
||||
free((char *) stream);
|
||||
free((char *) new_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_data->dev_id = (dev_t) 0;
|
||||
new_data->ino_id = cut_out_serial_id++;
|
||||
new_data->offset = data->offset;
|
||||
new_data->size = data->size;
|
||||
new_data->pos = 0;
|
||||
|
||||
stream->data = new_data;
|
||||
*new_stream = stream;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO update cut out streams to deal with update_size(). Seems hard.
|
||||
*/
|
||||
IsoStreamIface cut_out_stream_class = {
|
||||
4, /* version */
|
||||
"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,
|
||||
cut_out_update_size,
|
||||
cut_out_get_input_stream,
|
||||
cut_out_cmp_ino,
|
||||
cut_out_clone_stream
|
||||
|
||||
};
|
||||
|
||||
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 +600,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 +615,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 +642,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) {
|
||||
|
||||
if (data->offset >= (ssize_t) data->size) {
|
||||
return 0; /* EOF */
|
||||
}
|
||||
|
||||
|
||||
len = MIN(count, data->size - data->offset);
|
||||
memcpy(buf, data->buf + data->offset, len);
|
||||
data->offset += len;
|
||||
@ -311,38 +674,103 @@ 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)
|
||||
{
|
||||
MemStreamData *data;
|
||||
data = (MemStreamData*)stream->data;
|
||||
free(data->buf);
|
||||
if (data->buf != NULL)
|
||||
free(data->buf);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static
|
||||
int mem_update_size(IsoStream *stream)
|
||||
{
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
IsoStream* mem_get_input_stream(IsoStream *stream, int flag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int mem_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iso_stream_cmp_ino(s1, s2, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mem_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||
int flag)
|
||||
{
|
||||
MemStreamData *data, *new_data;
|
||||
IsoStream *stream;
|
||||
uint8_t *new_buf = NULL;
|
||||
|
||||
if (flag)
|
||||
return ISO_STREAM_NO_CLONE; /* unknown option required */
|
||||
|
||||
*new_stream = NULL;
|
||||
stream = calloc(1, sizeof(IsoStream));
|
||||
if (stream == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
stream->refcount = 1;
|
||||
stream->class = old_stream->class;
|
||||
new_data = calloc(1, sizeof(MemStreamData));
|
||||
if (new_data == NULL) {
|
||||
free((char *) stream);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = (MemStreamData *) old_stream->data;
|
||||
if (data->size > 0) {
|
||||
new_buf = calloc(1, data->size);
|
||||
if (new_buf == NULL) {
|
||||
free((char *) stream);
|
||||
free((char *) new_data);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
memcpy(new_buf, data->buf, data->size);
|
||||
}
|
||||
new_data->buf = new_buf;
|
||||
new_data->offset = -1;
|
||||
new_data->ino_id = mem_serial_id++;
|
||||
new_data->size = data->size;
|
||||
|
||||
stream->data = new_data;
|
||||
*new_stream = stream;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
IsoStreamIface mem_stream_class = {
|
||||
4, /* version */
|
||||
"mem ",
|
||||
mem_open,
|
||||
mem_close,
|
||||
mem_get_size,
|
||||
mem_read,
|
||||
mem_is_repeatable,
|
||||
mem_get_id,
|
||||
mem_get_name,
|
||||
mem_free
|
||||
mem_free,
|
||||
mem_update_size,
|
||||
mem_get_input_stream,
|
||||
mem_cmp_ino,
|
||||
mem_clone_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
|
||||
* 1 success, < 0 error
|
||||
*/
|
||||
int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream)
|
||||
{
|
||||
@ -358,7 +786,7 @@ int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream)
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
data = malloc(sizeof(MemStreamData));
|
||||
if (str == NULL) {
|
||||
if (data == NULL) {
|
||||
free(str);
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
@ -420,6 +848,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 +862,311 @@ 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);
|
||||
if (path == NULL) {
|
||||
name[0] = 0;
|
||||
return;
|
||||
}
|
||||
strncpy(name, path, PATH_MAX - 1);
|
||||
name[PATH_MAX - 1] = 0;
|
||||
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;
|
||||
}
|
||||
if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0) {
|
||||
return (s1 < s2 ? -1 : 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* 1 ok, 0 EOF, < 0 error
|
||||
*/
|
||||
int iso_stream_read_buffer(IsoStream *stream, char *buf, size_t count,
|
||||
size_t *got)
|
||||
{
|
||||
ssize_t result;
|
||||
|
||||
*got = 0;
|
||||
do {
|
||||
result = iso_stream_read(stream, buf + *got, count - *got);
|
||||
if (result < 0) {
|
||||
memset(buf + *got, 0, count - *got);
|
||||
return result;
|
||||
}
|
||||
if (result == 0)
|
||||
break;
|
||||
*got += result;
|
||||
} while (*got < count);
|
||||
|
||||
if (*got < count) {
|
||||
/* eof */
|
||||
memset(buf + *got, 0, count - *got);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* @param flag bit0= dig out most original stream (e.g. because from old image)
|
||||
@return 1=ok, md5 is valid,
|
||||
0= not ok,
|
||||
<0 fatal error, abort
|
||||
*/
|
||||
int iso_stream_make_md5(IsoStream *stream, char md5[16], int flag)
|
||||
{
|
||||
int ret, is_open = 0;
|
||||
char * buffer = NULL;
|
||||
void *ctx= NULL;
|
||||
off_t file_size;
|
||||
uint32_t b, nblocks;
|
||||
size_t got_bytes;
|
||||
IsoStream *input_stream;
|
||||
|
||||
LIBISO_ALLOC_MEM(buffer, char, 2048);
|
||||
if (flag & 1) {
|
||||
while(1) {
|
||||
input_stream = iso_stream_get_input_stream(stream, 0);
|
||||
if (input_stream == NULL)
|
||||
break;
|
||||
stream = input_stream;
|
||||
}
|
||||
}
|
||||
|
||||
if (! iso_stream_is_repeatable(stream))
|
||||
{ret = 0; goto ex;}
|
||||
ret = iso_md5_start(&ctx);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
ret = iso_stream_open(stream);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
is_open = 1;
|
||||
file_size = iso_stream_get_size(stream);
|
||||
nblocks = DIV_UP(file_size, 2048);
|
||||
for (b = 0; b < nblocks; ++b) {
|
||||
ret = iso_stream_read_buffer(stream, buffer, 2048, &got_bytes);
|
||||
if (ret < 0) {
|
||||
ret = 0;
|
||||
goto ex;
|
||||
}
|
||||
/* Do not use got_bytes to stay closer to IsoFileSrc processing */
|
||||
if (file_size - b * 2048 > 2048)
|
||||
ret = 2048;
|
||||
else
|
||||
ret = file_size - b * 2048;
|
||||
iso_md5_compute(ctx, buffer, ret);
|
||||
}
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (is_open)
|
||||
iso_stream_close(stream);
|
||||
if (ctx != NULL)
|
||||
iso_md5_end(&ctx, md5);
|
||||
LIBISO_FREE_MEM(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* API */
|
||||
int iso_stream_clone(IsoStream *old_stream, IsoStream **new_stream, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (old_stream->class->version < 4)
|
||||
return ISO_STREAM_NO_CLONE;
|
||||
ret = old_stream->class->clone_stream(old_stream, new_stream, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iso_stream_clone_filter_common(IsoStream *old_stream,
|
||||
IsoStream **new_stream,
|
||||
IsoStream **new_input, int flag)
|
||||
{
|
||||
IsoStream *stream, *input_stream;
|
||||
int ret;
|
||||
|
||||
*new_stream = NULL;
|
||||
*new_input = NULL;
|
||||
input_stream = iso_stream_get_input_stream(old_stream, 0);
|
||||
if (input_stream == NULL)
|
||||
return ISO_STREAM_NO_CLONE;
|
||||
stream = calloc(1, sizeof(IsoStream));
|
||||
if (stream == NULL)
|
||||
return ISO_OUT_OF_MEM;
|
||||
ret = iso_stream_clone(input_stream, new_input, 0);
|
||||
if (ret < 0) {
|
||||
free((char *) stream);
|
||||
return ret;
|
||||
}
|
||||
stream->class = old_stream->class;
|
||||
stream->refcount = 1;
|
||||
stream->data = NULL;
|
||||
*new_stream = stream;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/*
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* Copyright (c) 2009 - 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_STREAM_H_
|
||||
#define LIBISO_STREAM_H_
|
||||
@ -13,133 +15,101 @@
|
||||
*/
|
||||
#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
|
||||
/* IMPORTANT: Any change must be reflected by fsrc_clone_stream */
|
||||
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
|
||||
* Must provide at least PATH_MAX bytes. If no PATH_MAX is defined
|
||||
* then assume PATH_MAX = Libisofs_default_path_maX from libisofs.h
|
||||
*/
|
||||
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 stream for reading from a arbitrary memory buffer.
|
||||
* When the Stream refcount reach 0, the buffer is free(3).
|
||||
*
|
||||
* 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_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream);
|
||||
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_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);
|
||||
|
||||
|
||||
/**
|
||||
* Read the full required amount of data unless error or EOF occurs.
|
||||
* Fill missing bytes by 0s.
|
||||
* @param count Required amount
|
||||
* @param got Returns number of actually read bytes
|
||||
* @return
|
||||
* 1 no problem encountered, 0 EOF encountered, < 0 error
|
||||
*/
|
||||
int iso_stream_read_buffer(IsoStream *stream, char *buf, size_t count,
|
||||
size_t *got);
|
||||
|
||||
/**
|
||||
* @return 1=ok, md5 is valid,
|
||||
* 0= not ok
|
||||
* <0 fatal error, abort
|
||||
*/
|
||||
int iso_stream_make_md5(IsoStream *stream, char md5[16], int flag);
|
||||
|
||||
|
||||
/**
|
||||
* Create a clone of the input stream of old_stream and a roughly initialized
|
||||
* clone of old_stream which has the same class and refcount 1. Its data
|
||||
* pointer will be NULL and needs to be filled by an expert which knows how
|
||||
* to clone the data of old_stream.
|
||||
* @param old_stream The existing stream which is in process of cloning
|
||||
* @param new_stream Will return the uninitialized memory object which shall
|
||||
* later become the clone of old_stream.
|
||||
* @param new_input The clone of the input stream of old stream.
|
||||
* @param flag Submit 0 for now.
|
||||
* @return ISO_SUCCESS or an error code <0
|
||||
*/
|
||||
int iso_stream_clone_filter_common(IsoStream *old_stream,
|
||||
IsoStream **new_stream,
|
||||
IsoStream **new_input, int flag);
|
||||
|
||||
#endif /*STREAM_H_*/
|
||||
|
935
libisofs/system_area.c
Normal file
935
libisofs/system_area.c
Normal file
@ -0,0 +1,935 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Vreixo Formoso
|
||||
* Copyright (c) 2010 - 2011 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
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "system_area.h"
|
||||
#include "eltorito.h"
|
||||
#include "filesrc.h"
|
||||
#include "ecma119_tree.h"
|
||||
#include "image.h"
|
||||
#include "messages.h"
|
||||
#include "ecma119.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/*
|
||||
* Create a MBR for an isohybrid enabled ISOLINUX boot image.
|
||||
* See libisofs/make_isohybrid_mbr.c
|
||||
* Deprecated.
|
||||
*/
|
||||
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
|
||||
|
||||
/*
|
||||
* The New ISOLINUX MBR Producer.
|
||||
* Be cautious with changing parameters. Only few combinations are tested.
|
||||
*
|
||||
*/
|
||||
int make_isolinux_mbr(uint32_t *img_blocks, uint32_t boot_lba,
|
||||
uint32_t mbr_id, int head_count, int sector_count,
|
||||
int part_offset, int part_number, int fs_type,
|
||||
uint8_t *buf, int flag);
|
||||
|
||||
|
||||
/*
|
||||
* @param flag bit0= img_blocks is start address rather than end address:
|
||||
do not subtract 1
|
||||
*/
|
||||
static
|
||||
void iso_compute_cyl_head_sec(uint32_t *img_blocks, int hpc, int sph,
|
||||
uint32_t *end_lba, uint32_t *end_sec,
|
||||
uint32_t *end_head, uint32_t *end_cyl, int flag)
|
||||
{
|
||||
uint32_t secs;
|
||||
|
||||
/* Partition table unit is 512 bytes per sector, ECMA-119 unit is 2048 */
|
||||
if (*img_blocks >= 0x40000000)
|
||||
*img_blocks = 0x40000000 - 1; /* truncate rather than roll over */
|
||||
if (flag & 1)
|
||||
secs = *end_lba = *img_blocks * 4; /* first valid 512-lba */
|
||||
else
|
||||
secs = *end_lba = *img_blocks * 4 - 1; /* last valid 512-lba */
|
||||
*end_cyl = secs / (sph * hpc);
|
||||
secs -= *end_cyl * sph * hpc;
|
||||
*end_head = secs / sph;
|
||||
*end_sec = secs - *end_head * sph + 1; /* Sector count starts by 1 */
|
||||
if (*end_cyl >= 1024) {
|
||||
*end_cyl = 1023;
|
||||
*end_head = hpc - 1;
|
||||
*end_sec = sph;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Compute size and position of appended partitions.
|
||||
*/
|
||||
int iso_compute_append_partitions(Ecma119Image *t, int flag)
|
||||
{
|
||||
int ret, i, sa_type;
|
||||
uint32_t pos, size, add_pos = 0;
|
||||
struct stat stbuf;
|
||||
|
||||
sa_type = (t->system_area_options >> 2) & 0x3f;
|
||||
pos = (t->vol_space_size + t->ms_block);
|
||||
for (i = 0; i < ISO_MAX_PARTITIONS; i++) {
|
||||
if (t->appended_partitions[i] == NULL)
|
||||
continue;
|
||||
if (t->appended_partitions[i][0] == 0)
|
||||
continue;
|
||||
ret = stat(t->appended_partitions[i], &stbuf);
|
||||
if (ret == -1)
|
||||
return ISO_BAD_PARTITION_FILE;
|
||||
if (! S_ISREG(stbuf.st_mode))
|
||||
return ISO_BAD_PARTITION_FILE;
|
||||
size = ((stbuf.st_size + 2047) / 2048);
|
||||
if (sa_type == 3 && (pos % ISO_SUN_CYL_SIZE))
|
||||
add_pos = ISO_SUN_CYL_SIZE - (pos % ISO_SUN_CYL_SIZE);
|
||||
t->appended_part_prepad[i] = add_pos;
|
||||
t->appended_part_start[i] = pos + add_pos;
|
||||
t->appended_part_size[i] = size;
|
||||
pos += add_pos + size;
|
||||
t->total_size += (add_pos + size) * 2048;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Note: partition_offset and partition_size are counted in 2048 blocks
|
||||
*/
|
||||
static int write_mbr_partition_entry(int partition_number, int partition_type,
|
||||
uint32_t partition_offset, uint32_t partition_size,
|
||||
int sph, int hpc, uint8_t *buf, int flag)
|
||||
{
|
||||
uint8_t *wpt;
|
||||
uint32_t end_lba, end_sec, end_head, end_cyl;
|
||||
uint32_t start_lba, start_sec, start_head, start_cyl;
|
||||
uint32_t after_end;
|
||||
int i;
|
||||
|
||||
after_end = partition_offset + partition_size;
|
||||
iso_compute_cyl_head_sec(&partition_offset, hpc, sph,
|
||||
&start_lba, &start_sec, &start_head, &start_cyl, 1);
|
||||
iso_compute_cyl_head_sec(&after_end, hpc, sph,
|
||||
&end_lba, &end_sec, &end_head, &end_cyl, 0);
|
||||
wpt = buf + 446 + (partition_number - 1) * 16;
|
||||
|
||||
/* Not bootable */
|
||||
*(wpt++) = 0x00;
|
||||
|
||||
/* C/H/S of the start */
|
||||
*(wpt++) = start_head;
|
||||
*(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
|
||||
*(wpt++) = start_cyl & 0xff;
|
||||
|
||||
/* (partition type) */
|
||||
*(wpt++) = partition_type;
|
||||
|
||||
/* 3 bytes of C/H/S end */
|
||||
*(wpt++) = end_head;
|
||||
*(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
|
||||
*(wpt++) = end_cyl & 0xff;
|
||||
|
||||
/* LBA start in little endian */
|
||||
for (i = 0; i < 4; i++)
|
||||
*(wpt++) = (start_lba >> (8 * i)) & 0xff;
|
||||
|
||||
/* Number of sectors in partition, little endian */
|
||||
end_lba = end_lba - start_lba + 1;
|
||||
for (i = 0; i < 4; i++)
|
||||
*(wpt++) = (end_lba >> (8 * i)) & 0xff;
|
||||
|
||||
/* Afaik, partition tables are recognize donly with MBR signature */
|
||||
buf[510] = 0x55;
|
||||
buf[511] = 0xAA;
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* This is the gesture of grub-mkisofs --protective-msdos-label as explained by
|
||||
Vladimir Serbinenko <phcoder@gmail.com>, 2 April 2010, on grub-devel@gnu.org
|
||||
"Currently we use first and not last entry. You need to:
|
||||
1) Zero-fill 446-510
|
||||
2) Put 0x55, 0xAA into 510-512
|
||||
3) Put 0x80 (for bootable partition), 0, 2, 0 (C/H/S of the start), 0xcd
|
||||
(partition type), [3 bytes of C/H/S end], 0x01, 0x00, 0x00, 0x00 (LBA
|
||||
start in little endian), [LBA end in little endian] at 446-462
|
||||
"
|
||||
|
||||
"C/H/S end" means the CHS address of the last block in the partition.
|
||||
It seems that not "[LBA end in little endian]" but "number of blocks"
|
||||
should go into bytes 458-461. But with a start lba of 1, this is the
|
||||
same number.
|
||||
See also http://en.wikipedia.org/wiki/Master_boot_record
|
||||
|
||||
flag bit0= do not write 0x55, 0xAA to 510,511
|
||||
bit1= do not mark partition as bootable
|
||||
*/
|
||||
static
|
||||
int make_grub_msdos_label(uint32_t img_blocks, int sph, int hpc,
|
||||
uint8_t *buf, int flag)
|
||||
{
|
||||
uint8_t *wpt;
|
||||
uint32_t end_lba, end_sec, end_head, end_cyl;
|
||||
int i;
|
||||
|
||||
iso_compute_cyl_head_sec(&img_blocks, hpc, sph,
|
||||
&end_lba, &end_sec, &end_head, &end_cyl, 0);
|
||||
|
||||
/* 1) Zero-fill 446-510 */
|
||||
wpt = buf + 446;
|
||||
memset(wpt, 0, 64);
|
||||
|
||||
if (!(flag & 1)) {
|
||||
/* 2) Put 0x55, 0xAA into 510-512 (actually 510-511) */
|
||||
buf[510] = 0x55;
|
||||
buf[511] = 0xAA;
|
||||
}
|
||||
if (!(flag & 2)) {
|
||||
/* 3) Put 0x80 (for bootable partition), */
|
||||
*(wpt++) = 0x80;
|
||||
} else {
|
||||
*(wpt++) = 0;
|
||||
}
|
||||
|
||||
/* 0, 2, 0 (C/H/S of the start), */
|
||||
*(wpt++) = 0;
|
||||
*(wpt++) = 2;
|
||||
*(wpt++) = 0;
|
||||
|
||||
/* 0xcd (partition type) */
|
||||
*(wpt++) = 0xcd;
|
||||
|
||||
/* [3 bytes of C/H/S end], */
|
||||
*(wpt++) = end_head;
|
||||
*(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
|
||||
*(wpt++) = end_cyl & 0xff;
|
||||
|
||||
|
||||
/* 0x01, 0x00, 0x00, 0x00 (LBA start in little endian), */
|
||||
*(wpt++) = 0x01;
|
||||
*(wpt++) = 0x00;
|
||||
*(wpt++) = 0x00;
|
||||
*(wpt++) = 0x00;
|
||||
|
||||
/* [LBA end in little endian] */
|
||||
for (i = 0; i < 4; i++)
|
||||
*(wpt++) = (end_lba >> (8 * i)) & 0xff;
|
||||
|
||||
/* at 446-462 */
|
||||
if (wpt - buf != 462) {
|
||||
fprintf(stderr,
|
||||
"libisofs: program error in make_grub_msdos_label: \"assert 462\"\n");
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* @param flag bit0= zeroize partitions entries 2, 3, 4
|
||||
*/
|
||||
static
|
||||
int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset,
|
||||
int sph, int hpc, uint8_t *buf, int flag)
|
||||
{
|
||||
uint8_t *wpt;
|
||||
uint32_t end_lba, end_sec, end_head, end_cyl;
|
||||
uint32_t start_lba, start_sec, start_head, start_cyl;
|
||||
int i;
|
||||
|
||||
iso_compute_cyl_head_sec(&partition_offset, hpc, sph,
|
||||
&start_lba, &start_sec, &start_head, &start_cyl, 1);
|
||||
iso_compute_cyl_head_sec(&img_blocks, hpc, sph,
|
||||
&end_lba, &end_sec, &end_head, &end_cyl, 0);
|
||||
wpt = buf + 446;
|
||||
|
||||
/* Let pass only legal bootability values */
|
||||
if (*wpt != 0 && *wpt != 0x80)
|
||||
(*wpt) = 0;
|
||||
wpt++;
|
||||
|
||||
/* C/H/S of the start */
|
||||
*(wpt++) = start_head;
|
||||
*(wpt++) = start_sec | ((start_cyl & 0x300) >> 2);
|
||||
*(wpt++) = start_cyl & 0xff;
|
||||
|
||||
/* (partition type) */
|
||||
wpt++;
|
||||
|
||||
/* 3 bytes of C/H/S end */
|
||||
*(wpt++) = end_head;
|
||||
*(wpt++) = end_sec | ((end_cyl & 0x300) >> 2);
|
||||
*(wpt++) = end_cyl & 0xff;
|
||||
|
||||
/* LBA start in little endian */
|
||||
for (i = 0; i < 4; i++)
|
||||
*(wpt++) = (start_lba >> (8 * i)) & 0xff;
|
||||
|
||||
/* Number of sectors in partition, little endian */
|
||||
end_lba = end_lba - start_lba + 1;
|
||||
for (i = 0; i < 4; i++)
|
||||
*(wpt++) = (end_lba >> (8 * i)) & 0xff;
|
||||
|
||||
if (wpt - buf != 462) {
|
||||
fprintf(stderr,
|
||||
"libisofs: program error in iso_offset_partition_start: \"assert 462\"\n");
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
if (flag & 1) /* zeroize the other partition entries */
|
||||
memset(wpt, 0, 3 * 16);
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int boot_nodes_from_iso_path(Ecma119Image *t, char *path,
|
||||
IsoNode **iso_node, Ecma119Node **ecma_node,
|
||||
char *purpose, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iso_tree_path_to_node(t->image, path, iso_node);
|
||||
if (ret <= 0) {
|
||||
iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0,
|
||||
"Cannot find in ISO image: %s '%s'", purpose, path);
|
||||
return ISO_BOOT_FILE_MISSING;
|
||||
}
|
||||
if ((*iso_node)->type != LIBISO_FILE) {
|
||||
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||
"Designated boot file is not a data file: '%s'", path);
|
||||
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||
}
|
||||
|
||||
*ecma_node= ecma119_search_iso_node(t, *iso_node);
|
||||
if (*ecma_node == NULL) {
|
||||
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||
"Program error: IsoFile has no Ecma119Node: '%s'", path);
|
||||
return ISO_ASSERT_FAILURE;
|
||||
} else {
|
||||
if ((*ecma_node)->type != ECMA119_FILE) {
|
||||
iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||
"Program error: Ecma119Node of IsoFile is no ECMA119_FILE: '%s'",
|
||||
path);
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* This function was implemented according to doc/boot_sectors.txt section
|
||||
"MIPS Volume Header" which was derived by Thomas Schmitt from
|
||||
cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based
|
||||
on work of Florian Lohoff and Thiemo Seufer who possibly learned from
|
||||
documents of MIPS Computer Systems, Inc. and Silicon Graphics Computer
|
||||
Systems, Inc.
|
||||
This function itself is entirely under copyright (C) 2010 Thomas Schmitt.
|
||||
*/
|
||||
static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag)
|
||||
{
|
||||
char *namept, *name_field;
|
||||
uint32_t num_cyl, idx, blocks, num, checksum;
|
||||
off_t image_size;
|
||||
static uint32_t bps = 512, spt = 32;
|
||||
Ecma119Node *ecma_node;
|
||||
IsoNode *node;
|
||||
IsoStream *stream;
|
||||
off_t file_size;
|
||||
uint32_t file_lba;
|
||||
int ret;
|
||||
|
||||
/* Bytes 512 to 32767 may come from image or external file */
|
||||
memset(buf, 0, 512);
|
||||
|
||||
image_size = t->curblock * 2048;
|
||||
|
||||
/* 0 - 3 | 0x0be5a941 | Magic number */
|
||||
iso_msb(buf, 0x0be5a941, 4);
|
||||
|
||||
/* 28 - 29 | num_cyl_l | Number of usable cylinder, lower two bytes */
|
||||
num_cyl = (image_size + (bps * spt) - 1) / (bps * spt);
|
||||
iso_msb(buf + 28, num_cyl & 0xffff, 2);
|
||||
|
||||
/* 32 - 33 | 1 | Number of tracks per cylinder */
|
||||
iso_msb(buf + 32, 1, 2);
|
||||
|
||||
/* 35 - 35 | num_cyl_h | Number of usable cylinders, high byte */
|
||||
buf[35] = (num_cyl >> 16) & 0xff;
|
||||
|
||||
/* 38 - 39 | 32 | Sectors per track */
|
||||
iso_msb(buf + 38, spt, 2);
|
||||
|
||||
/* 40 - 41 | 512 | Bytes per sector */
|
||||
iso_msb(buf + 40, bps, 2);
|
||||
|
||||
/* 44 - 47 | 0x00000034 | Controller characteristics */
|
||||
iso_msb(buf + 44, 0x00000034, 4);
|
||||
|
||||
/* 72 - 87 | ========== | Volume Directory Entry 1 */
|
||||
/* 72 - 79 | boot_name | Boot file basename */
|
||||
/* 80 - 83 | boot_block | ISO 9660 LBA of boot file * 4 */
|
||||
/* 84 - 87 | boot_bytes | File length in bytes */
|
||||
/* 88 - 311 | 0 | Volume Directory Entries 2 to 15 */
|
||||
|
||||
for (idx = 0; (int) idx < t->image->num_mips_boot_files; idx++) {
|
||||
ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx],
|
||||
&node, &ecma_node, "MIPS boot file", 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
namept = (char *) iso_node_get_name(node);
|
||||
name_field = (char *) (buf + (72 + 16 * idx));
|
||||
strncpy(name_field, namept, 8);
|
||||
|
||||
file_lba = ecma_node->info.file->sections[0].block;
|
||||
|
||||
iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4);
|
||||
|
||||
stream = iso_file_get_stream((IsoFile *) node);
|
||||
file_size = iso_stream_get_size(stream);
|
||||
|
||||
/* Shall i really round up to 2048 ? Steve says yes.*/
|
||||
iso_msb(buf + (72 + 16 * idx) + 12,
|
||||
((file_size + 2047) / 2048 ) * 2048, 4);
|
||||
|
||||
}
|
||||
|
||||
/* 408 - 411 | part_blks | Number of 512 byte blocks in partition */
|
||||
blocks = (image_size + bps - 1) / bps;
|
||||
iso_msb(buf + 408, blocks, 4);
|
||||
/* 416 - 419 | 0 | Partition is volume header */
|
||||
iso_msb(buf + 416, 0, 4);
|
||||
|
||||
/* 432 - 435 | part_blks | Number of 512 byte blocks in partition */
|
||||
iso_msb(buf + 432, blocks, 4);
|
||||
iso_msb(buf + 444, 6, 4);
|
||||
|
||||
/* 504 - 507 | head_chk | Volume header checksum
|
||||
The two's complement of bytes 0 to 503 read
|
||||
as big endian unsigned 32 bit:
|
||||
sum(32-bit-words) + head_chk == 0
|
||||
*/
|
||||
checksum = 0;
|
||||
for (idx = 0; idx < 504; idx += 4) {
|
||||
num = iso_read_msb(buf + idx, 4);
|
||||
/* Addition modulo a natural number is commutative and associative.
|
||||
Thus the inverse of a sum is the sum of the inverses of the addends.
|
||||
*/
|
||||
checksum -= num;
|
||||
}
|
||||
iso_msb(buf + 504, checksum, 4);
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* The following two functions were implemented according to
|
||||
doc/boot_sectors.txt section "MIPS Little Endian" which was derived
|
||||
by Thomas Schmitt from
|
||||
cdrkit-1.1.10/genisoimage/boot-mipsel.c by Steve McIntyre which is based
|
||||
on work of Florian Lohoff and Thiemo Seufer,
|
||||
and from <elf.h> by Free Software Foundation, Inc.
|
||||
|
||||
Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read the necessary ELF information from the first MIPS boot file.
|
||||
* This is done before image writing starts.
|
||||
*/
|
||||
int iso_read_mipsel_elf(Ecma119Image *t, int flag)
|
||||
{
|
||||
uint32_t phdr_adr, todo, count;
|
||||
int ret;
|
||||
uint8_t *elf_buf = NULL;
|
||||
IsoNode *iso_node;
|
||||
Ecma119Node *ecma_node;
|
||||
IsoStream *stream;
|
||||
|
||||
if (t->image->num_mips_boot_files <= 0)
|
||||
{ret = ISO_SUCCESS; goto ex;}
|
||||
|
||||
LIBISO_ALLOC_MEM(elf_buf, uint8_t, 2048);
|
||||
ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
|
||||
&iso_node, &ecma_node, "MIPS boot file", 0);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
stream = iso_file_get_stream((IsoFile *) iso_node);
|
||||
|
||||
ret = iso_stream_open(stream);
|
||||
if (ret < 0) {
|
||||
iso_msg_submit(t->image->id, ret, 0,
|
||||
"Cannot open designated MIPS boot file '%s'",
|
||||
t->image->mips_boot_file_paths[0]);
|
||||
goto ex;
|
||||
}
|
||||
ret = iso_stream_read(stream, elf_buf, 32);
|
||||
if (ret != 32) {
|
||||
cannot_read:;
|
||||
iso_stream_close(stream);
|
||||
iso_msg_submit(t->image->id, ret, 0,
|
||||
"Cannot read from designated MIPS boot file '%s'",
|
||||
t->image->mips_boot_file_paths[0]);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
|
||||
/* 24 - 27 | e_entry | Entry point virtual address */
|
||||
t->mipsel_e_entry = iso_read_lsb(elf_buf + 24, 4);
|
||||
|
||||
/* 28 - 31 | e_phoff | Program header table file offset */
|
||||
phdr_adr = iso_read_lsb(elf_buf + 28, 4);
|
||||
|
||||
/* Skip stream up to byte address phdr_adr */
|
||||
todo = phdr_adr - 32;
|
||||
while (todo > 0) {
|
||||
if (todo > 2048)
|
||||
count = 2048;
|
||||
else
|
||||
count = todo;
|
||||
todo -= count;
|
||||
ret = iso_stream_read(stream, elf_buf, count);
|
||||
if (ret != (int) count)
|
||||
goto cannot_read;
|
||||
}
|
||||
ret = iso_stream_read(stream, elf_buf, 20);
|
||||
if (ret != 20)
|
||||
goto cannot_read;
|
||||
|
||||
/* 4 - 7 | p_offset | Segment file offset */
|
||||
t->mipsel_p_offset = iso_read_lsb(elf_buf + 4, 4);
|
||||
|
||||
/* 8 - 11 | p_vaddr | Segment virtual address */
|
||||
t->mipsel_p_vaddr = iso_read_lsb(elf_buf + 8, 4);
|
||||
|
||||
/* 16 - 19 | p_filesz | Segment size in file */
|
||||
t->mipsel_p_filesz = iso_read_lsb(elf_buf + 16, 4);
|
||||
|
||||
iso_stream_close(stream);
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(elf_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write DEC Bootblock from previously read ELF parameters.
|
||||
* This is done when image writing has already begun.
|
||||
*/
|
||||
static int make_mipsel_boot_block(Ecma119Image *t, uint8_t *buf, int flag)
|
||||
{
|
||||
int ret;
|
||||
uint32_t seg_size, seg_start;
|
||||
IsoNode *iso_node;
|
||||
Ecma119Node *ecma_node;
|
||||
|
||||
/* Bytes 512 to 32767 may come from image or external file */
|
||||
memset(buf, 0, 512);
|
||||
|
||||
if (t->image->num_mips_boot_files <= 0)
|
||||
return ISO_SUCCESS;
|
||||
|
||||
ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0],
|
||||
&iso_node, &ecma_node, "MIPS boot file", 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* 8 - 11 | 0x0002757a | Magic number */
|
||||
iso_lsb(buf + 8, 0x0002757a, 4);
|
||||
|
||||
/* 12 - 15 | 1 | Mode 1: Multi extent boot */
|
||||
iso_lsb(buf + 12, 1, 4);
|
||||
|
||||
/* 16 - 19 | load_adr | Load address */
|
||||
iso_lsb(buf + 16, t->mipsel_p_vaddr, 4);
|
||||
|
||||
/* 20 - 23 | exec_adr | Execution address */
|
||||
iso_lsb(buf + 20, t->mipsel_e_entry, 4);
|
||||
|
||||
/* 24 - 27 | seg_size | Segment size in file. */
|
||||
seg_size = (t->mipsel_p_filesz + 511) / 512;
|
||||
iso_lsb(buf + 24, seg_size, 4);
|
||||
|
||||
/* 28 - 31 | seg_start | Segment file offset */
|
||||
seg_start = ecma_node->info.file->sections[0].block * 4
|
||||
+ (t->mipsel_p_offset + 511) / 512;
|
||||
iso_lsb(buf + 28, seg_start, 4);
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* The following two functions were implemented according to
|
||||
doc/boot_sectors.txt section "SUN Disk Label and boot images" which
|
||||
was derived by Thomas Schmitt from
|
||||
cdrtools-2.01.01a77/mkisofs/sunlabel.h
|
||||
cdrtools-2.01.01a77/mkisofs/mkisofs.8
|
||||
by Joerg Schilling
|
||||
|
||||
Both functions are entirely under copyright (C) 2010 Thomas Schmitt.
|
||||
*/
|
||||
|
||||
/* @parm flag bit0= copy from next lower valid partition table entry
|
||||
*/
|
||||
static int write_sun_partition_entry(int partition_number,
|
||||
char *appended_partitions[],
|
||||
uint32_t partition_offset[], uint32_t partition_size[],
|
||||
uint32_t cyl_size, uint8_t *buf, int flag)
|
||||
{
|
||||
uint8_t *wpt;
|
||||
int read_idx, i;
|
||||
|
||||
if (partition_number < 1 || partition_number > 8)
|
||||
return ISO_ASSERT_FAILURE;
|
||||
|
||||
/* 142 - 173 | ========== | 8 partition entries of 4 bytes */
|
||||
wpt = buf + 142 + (partition_number - 1) * 4;
|
||||
if (partition_number == 1)
|
||||
iso_msb(wpt, 4, 2); /* 4 = User partition */
|
||||
else
|
||||
iso_msb(wpt, 2, 2); /* 2 = Root partition with boot image */
|
||||
iso_msb(wpt + 2, 0x10, 2); /* Permissions: 0x10 = read-only */
|
||||
|
||||
/* 444 - 507 | ========== | Partition table */
|
||||
wpt = buf + 444 + (partition_number - 1) * 8;
|
||||
read_idx = partition_number - 1;
|
||||
if (flag & 1) {
|
||||
/* Search next lower valid partition table entry. #1 is default */
|
||||
for (read_idx = partition_number - 2; read_idx > 0; read_idx--)
|
||||
if (appended_partitions[read_idx] != NULL)
|
||||
if (appended_partitions[read_idx][0] != 0)
|
||||
break;
|
||||
}
|
||||
iso_msb(wpt, partition_offset[read_idx] / (uint32_t) ISO_SUN_CYL_SIZE, 4);
|
||||
iso_msb(wpt + 4, partition_size[read_idx] * 4, 4);
|
||||
|
||||
/* 510 - 511 | checksum | The result of exoring 2-byte words 0 to 254 */
|
||||
buf[510] = buf[511] = 0;
|
||||
for (i = 0; i < 510; i += 2) {
|
||||
buf[510] ^= buf[i];
|
||||
buf[511] ^= buf[i + 1];
|
||||
}
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write SUN Disk Label with ISO in partition 1 and unused 2 to 8
|
||||
*/
|
||||
static int make_sun_disk_label(Ecma119Image *t, uint8_t *buf, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Bytes 512 to 32767 may come from image or external file */
|
||||
memset(buf, 0, 512);
|
||||
|
||||
/* 0 - 127 | label | ASCII Label */
|
||||
if (t->ascii_disc_label[0])
|
||||
strncpy((char *) buf, t->ascii_disc_label, 128);
|
||||
else
|
||||
strcpy((char *) buf,
|
||||
"CD-ROM Disc with Sun sparc boot created by libisofs");
|
||||
|
||||
/* 128 - 131 | 1 | Layout version */
|
||||
iso_msb(buf + 128, 1, 4);
|
||||
|
||||
/* 140 - 141 | 8 | Number of partitions */
|
||||
iso_msb(buf + 140, 8, 2);
|
||||
|
||||
/* 188 - 191 | 0x600ddeee | vtoc sanity */
|
||||
iso_msb(buf + 188, 0x600ddeee, 4);
|
||||
|
||||
/* 420 - 421 | 350 | Rotations per minute */
|
||||
iso_msb(buf + 420, 350, 2);
|
||||
|
||||
/* 422 - 423 | 2048 | Number of physical cylinders (fixely 640 MB) */
|
||||
iso_msb(buf + 422, 2048, 2);
|
||||
|
||||
/* 430 - 431 | 1 | interleave factor */
|
||||
iso_msb(buf + 430, 1, 2);
|
||||
|
||||
/* 432 - 433 | 2048 | Number of data cylinders (fixely 640 MB) */
|
||||
iso_msb(buf + 432, 2048, 2);
|
||||
|
||||
/* 436 - 437 | 1 | Number of heads per cylinder (1 cyl = 320 kB)*/
|
||||
iso_msb(buf + 436, 1, 2);
|
||||
|
||||
/* 438 - 439 | 640 | Number of sectors per head (1 head = 320 kB) */
|
||||
iso_msb(buf + 438, 640, 2);
|
||||
|
||||
/* 508 - 509 | 0xdabe | Magic Number */
|
||||
iso_msb(buf + 508, 0xdabe, 2);
|
||||
|
||||
/* Set partition 1 to describe ISO image and compute checksum */
|
||||
t->appended_part_start[0] = 0;
|
||||
t->appended_part_size[0] = t->curblock;
|
||||
ret = write_sun_partition_entry(1, t->appended_partitions,
|
||||
t->appended_part_start, t->appended_part_size,
|
||||
ISO_SUN_CYL_SIZE, buf, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
|
||||
{
|
||||
int ret, int_img_blocks, sa_type, i, will_append = 0;
|
||||
int first_partition = 1, last_partition = 4;
|
||||
uint32_t img_blocks;
|
||||
|
||||
if ((t == NULL) || (buf == NULL)) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
/* set buf to 0s */
|
||||
memset(buf, 0, 16 * BLOCK_SIZE);
|
||||
|
||||
sa_type = (t->system_area_options >> 2) & 0x3f;
|
||||
if (sa_type == 3) {
|
||||
first_partition = 2;
|
||||
last_partition = 8;
|
||||
}
|
||||
for (i = first_partition - 1; i <= last_partition - 1; i++)
|
||||
if (t->appended_partitions[i] != NULL) {
|
||||
will_append = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
img_blocks = t->curblock;
|
||||
if (t->system_area_data != NULL) {
|
||||
/* Write more or less opaque boot image */
|
||||
memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE);
|
||||
|
||||
} else if (sa_type == 0 && t->catalog != NULL &&
|
||||
(t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
|
||||
/* Check for isolinux image with magic number of 3.72 and produce
|
||||
an MBR from our built-in template. (Deprecated since 31 Mar 2010)
|
||||
*/
|
||||
if (img_blocks < 0x80000000) {
|
||||
int_img_blocks= img_blocks;
|
||||
} else {
|
||||
int_img_blocks= 0x7ffffff0;
|
||||
}
|
||||
ret = make_isohybrid_mbr(t->bootsrc[0]->sections[0].block,
|
||||
&int_img_blocks, (char*)buf, 0);
|
||||
if (ret != 1) {
|
||||
/* error, it should never happen */
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
if (sa_type == 0 && (t->system_area_options & 1)) {
|
||||
/* Write GRUB protective msdos label, i.e. a simple partition table */
|
||||
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
|
||||
t->partition_heads_per_cyl, buf, 0);
|
||||
if (ret != ISO_SUCCESS) /* error should never happen */
|
||||
return ISO_ASSERT_FAILURE;
|
||||
} else if(sa_type == 0 && (t->system_area_options & 2)) {
|
||||
/* Patch externally provided system area as isohybrid MBR */
|
||||
if (t->catalog == NULL || t->system_area_data == NULL) {
|
||||
/* isohybrid makes only sense together with ISOLINUX boot image
|
||||
and externally provided System Area.
|
||||
*/
|
||||
return ISO_ISOLINUX_CANT_PATCH;
|
||||
}
|
||||
ret = make_isolinux_mbr(&img_blocks, t->bootsrc[0]->sections[0].block,
|
||||
(uint32_t) 0, t->partition_heads_per_cyl,
|
||||
t->partition_secs_per_head, 0, 1, 0x17, buf, 1);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
} else if (sa_type == 1) {
|
||||
ret = make_mips_volume_header(t, buf, 0);
|
||||
if (ret != ISO_SUCCESS)
|
||||
return ret;
|
||||
} else if (sa_type == 2) {
|
||||
ret = make_mipsel_boot_block(t, buf, 0);
|
||||
if (ret != ISO_SUCCESS)
|
||||
return ret;
|
||||
} else if ((t->partition_offset > 0 || will_append) && sa_type == 0) {
|
||||
/* Write a simple partition table. */
|
||||
ret = make_grub_msdos_label(img_blocks, t->partition_secs_per_head,
|
||||
t->partition_heads_per_cyl, buf, 2);
|
||||
if (ret != ISO_SUCCESS) /* error should never happen */
|
||||
return ISO_ASSERT_FAILURE;
|
||||
if (t->partition_offset == 0) {
|
||||
/* Re-write partion entry 1 : start at 0, type Linux */
|
||||
ret = write_mbr_partition_entry(1, 0x83, 0, img_blocks,
|
||||
t->partition_secs_per_head, t->partition_heads_per_cyl,
|
||||
buf, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
} else if (sa_type == 3) {
|
||||
ret = make_sun_disk_label(t, buf, 0);
|
||||
if (ret != ISO_SUCCESS)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (t->partition_offset > 0 && sa_type == 0) {
|
||||
/* Adjust partition table to partition offset */
|
||||
img_blocks = t->curblock; /* value might be altered */
|
||||
ret = iso_offset_partition_start(img_blocks, t->partition_offset,
|
||||
t->partition_secs_per_head,
|
||||
t->partition_heads_per_cyl, buf, 1);
|
||||
if (ret != ISO_SUCCESS) /* error should never happen */
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
/* This eventually overwrites the partition table entries made so far */
|
||||
for (i = first_partition - 1; i <= last_partition - 1; i++) {
|
||||
if (t->appended_partitions[i] == NULL)
|
||||
continue;
|
||||
if (sa_type == 3) {
|
||||
ret = write_sun_partition_entry(i + 1, t->appended_partitions,
|
||||
t->appended_part_start, t->appended_part_size,
|
||||
ISO_SUN_CYL_SIZE,
|
||||
buf, t->appended_partitions[i][0] == 0);
|
||||
} else {
|
||||
ret = write_mbr_partition_entry(i + 1, t->appended_part_types[i],
|
||||
t->appended_part_start[i], t->appended_part_size[i],
|
||||
t->partition_secs_per_head, t->partition_heads_per_cyl,
|
||||
buf, 0);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/* Choose *heads_per_cyl so that
|
||||
- *heads_per_cyl * secs_per_head * 1024 >= imgsize / 512
|
||||
- *heads_per_cyl * secs_per_head is divisible by 4
|
||||
- it is as small as possible (to reduce aligment overhead)
|
||||
- it is <= 255
|
||||
@return 1= success , 0= cannot achieve goals
|
||||
*/
|
||||
static
|
||||
int try_sph(off_t imgsize, int secs_per_head, int *heads_per_cyl, int flag)
|
||||
{
|
||||
off_t hd_blocks, hpc;
|
||||
|
||||
hd_blocks= imgsize / 512;
|
||||
hpc = hd_blocks / secs_per_head / 1024;
|
||||
if (hpc * secs_per_head * 1024 < hd_blocks)
|
||||
hpc++;
|
||||
if ((secs_per_head % 4) == 0) {
|
||||
;
|
||||
} else if ((secs_per_head % 2) == 0) {
|
||||
hpc += (hpc % 2);
|
||||
} else if(hpc % 4) {
|
||||
hpc += 4 - (hpc % 4);
|
||||
}
|
||||
if (hpc > 255)
|
||||
return 0;
|
||||
*heads_per_cyl = hpc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iso_align_isohybrid(Ecma119Image *t, int flag)
|
||||
{
|
||||
int sa_type, ret, always_align;
|
||||
uint32_t img_blocks;
|
||||
off_t imgsize, cylsize = 0, frac;
|
||||
char *msg = NULL;
|
||||
|
||||
LIBISO_ALLOC_MEM(msg, char, 160);
|
||||
sa_type = (t->system_area_options >> 2) & 0x3f;
|
||||
if (sa_type != 0)
|
||||
{ret = ISO_SUCCESS; goto ex;}
|
||||
always_align = (t->system_area_options >> 8) & 3;
|
||||
|
||||
img_blocks = t->curblock + t->tail_blocks;
|
||||
imgsize = ((off_t) img_blocks) * (off_t) 2048;
|
||||
if (((t->system_area_options & 3) || always_align)
|
||||
&& (off_t) (t->partition_heads_per_cyl * t->partition_secs_per_head
|
||||
* 1024) * (off_t) 512 < imgsize) {
|
||||
/* Choose small values which can represent the image size */
|
||||
/* First try 32 sectors per head */
|
||||
ret = try_sph(imgsize, 32, &(t->partition_heads_per_cyl), 0);
|
||||
if (ret == 1) {
|
||||
t->partition_secs_per_head = 32;
|
||||
} else {
|
||||
/* Did not work with 32. Try 63 */
|
||||
t->partition_secs_per_head = 63;
|
||||
ret = try_sph(imgsize, 63, &(t->partition_heads_per_cyl), 0);
|
||||
if (ret != 1)
|
||||
t->partition_heads_per_cyl = 255;
|
||||
}
|
||||
cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head *512;
|
||||
frac = imgsize % cylsize;
|
||||
sprintf(msg, "Automatically adjusted MBR geometry to %d/%d/%d",
|
||||
(int) (imgsize / cylsize + !!frac),
|
||||
t->partition_heads_per_cyl, t->partition_secs_per_head);
|
||||
iso_msgs_submit(0, msg, 0, "NOTE", 0);
|
||||
}
|
||||
|
||||
if (always_align >= 2)
|
||||
{ret = ISO_SUCCESS; goto ex;}
|
||||
|
||||
cylsize = 0;
|
||||
if (t->catalog != NULL &&
|
||||
(t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) {
|
||||
/* Check for isolinux image with magic number of 3.72 and produce
|
||||
an MBR from our built-in template. (Deprecated since 31 Mar 2010)
|
||||
*/
|
||||
if (img_blocks >= 0x40000000)
|
||||
{ret = ISO_SUCCESS; goto ex;}
|
||||
cylsize = 64 * 32 * 512;
|
||||
} else if ((t->system_area_options & 2) || always_align) {
|
||||
/* Patch externally provided system area as isohybrid MBR */
|
||||
if (t->catalog == NULL || t->system_area_data == NULL) {
|
||||
/* isohybrid makes only sense together with ISOLINUX boot image
|
||||
and externally provided System Area.
|
||||
*/
|
||||
{ret = ISO_ISOLINUX_CANT_PATCH; goto ex;}
|
||||
}
|
||||
cylsize = t->partition_heads_per_cyl * t->partition_secs_per_head
|
||||
* 512;
|
||||
}
|
||||
if (cylsize == 0)
|
||||
{ret = ISO_SUCCESS; goto ex;}
|
||||
if (((double) imgsize) / (double) cylsize > 1024.0) {
|
||||
iso_msgs_submit(0,
|
||||
"Image size exceeds 1024 cylinders. Cannot align partition.",
|
||||
0, "WARNING", 0);
|
||||
{ret = ISO_SUCCESS; goto ex;}
|
||||
}
|
||||
|
||||
frac = imgsize % cylsize;
|
||||
imgsize += (frac > 0 ? cylsize - frac : 0);
|
||||
|
||||
frac = imgsize - ((off_t) img_blocks) * (off_t) 2048;
|
||||
if (frac == 0)
|
||||
{ret = ISO_SUCCESS; goto ex;}
|
||||
if (frac % 2048) {
|
||||
sprintf(msg,
|
||||
"Cylinder size %d not divisible by 2048. Cannot align partition.",
|
||||
(int) cylsize);
|
||||
iso_msgs_submit(0, msg, 0, "WARNING", 0);
|
||||
} else {
|
||||
t->tail_blocks += frac / 2048;
|
||||
}
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
LIBISO_FREE_MEM(msg);
|
||||
return ret;
|
||||
}
|
66
libisofs/system_area.h
Normal file
66
libisofs/system_area.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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
|
||||
* or later 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);
|
||||
|
||||
/**
|
||||
* Adjust t->tail_blocks to the eventual alignment needs of isohybrid booting.
|
||||
*/
|
||||
int iso_align_isohybrid(Ecma119Image *t, int flag);
|
||||
|
||||
|
||||
/**
|
||||
* Read the necessary ELF information from the first MIPS boot file.
|
||||
* See doc/boot_sectors.txt "DEC Boot Block" for "MIPS Little Endian".
|
||||
*/
|
||||
int iso_read_mipsel_elf(Ecma119Image *t, int flag);
|
||||
|
||||
|
||||
/* Compute size and position of appended partitions.
|
||||
*/
|
||||
int iso_compute_append_partitions(Ecma119Image *t, int flag);
|
||||
|
||||
#endif /* SYSTEM_AREA_H_ */
|
467
libisofs/tree.c
467
libisofs/tree.c
@ -1,15 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
* Copyright (c) 2011 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.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions that act on the iso tree.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "node.h"
|
||||
#include "image.h"
|
||||
@ -25,6 +31,7 @@
|
||||
#include <stdio.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
|
||||
/**
|
||||
* Add a new directory to the iso tree.
|
||||
*
|
||||
@ -256,6 +263,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.
|
||||
@ -396,12 +478,12 @@ int iso_tree_remove_exclude(IsoImage *image, const char *path)
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
for (i = 0; i < image->nexcludes; ++i) {
|
||||
for (i = 0; (int) i < image->nexcludes; ++i) {
|
||||
if (strcmp(image->excludes[i], path) == 0) {
|
||||
/* exclude found */
|
||||
free(image->excludes[i]);
|
||||
--image->nexcludes;
|
||||
for (j = i; j < image->nexcludes; ++j) {
|
||||
for (j = i; (int) j < image->nexcludes; ++j) {
|
||||
image->excludes[j] = image->excludes[j+1];
|
||||
}
|
||||
image->excludes = realloc(image->excludes, image->nexcludes *
|
||||
@ -475,6 +557,138 @@ 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;
|
||||
}
|
||||
|
||||
/* 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, &file);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -547,11 +761,16 @@ int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir)
|
||||
|
||||
ret = iso_file_source_open(dir);
|
||||
if (ret < 0) {
|
||||
char *path = iso_file_source_get_path(dir);
|
||||
path = iso_file_source_get_path(dir);
|
||||
/* instead of the probable error, we throw a sorry event */
|
||||
ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret,
|
||||
"Can't open dir %s", path);
|
||||
free(path);
|
||||
if (path != NULL) {
|
||||
ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret,
|
||||
"Can't open dir %s", path);
|
||||
free(path);
|
||||
} else {
|
||||
ret = iso_msg_submit(image->id, ISO_NULL_POINTER, ret,
|
||||
"Can't open dir. NULL pointer caught as dir name");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -571,6 +790,11 @@ int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir)
|
||||
}
|
||||
|
||||
path = iso_file_source_get_path(file);
|
||||
if (path == NULL) {
|
||||
ret = iso_msg_submit(image->id, ISO_NULL_POINTER, ret,
|
||||
"NULL pointer caught as file path");
|
||||
return ret;
|
||||
}
|
||||
name = strrchr(path, '/') + 1;
|
||||
|
||||
if (image->follow_symlinks) {
|
||||
@ -633,7 +857,7 @@ int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir)
|
||||
ret = iso_dir_insert(parent, new, pos, replace);
|
||||
if (ret < 0) {
|
||||
iso_node_unref(new);
|
||||
if (ret != ISO_NODE_NAME_NOT_UNIQUE) {
|
||||
if (ret != (int) ISO_NODE_NAME_NOT_UNIQUE) {
|
||||
/* error */
|
||||
goto dir_rec_continue;
|
||||
} else {
|
||||
@ -706,7 +930,7 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
|
||||
int result;
|
||||
IsoNode *n;
|
||||
IsoDir *dir;
|
||||
char *ptr, *brk_info, *component;
|
||||
char *ptr, *brk_info = NULL, *component;
|
||||
|
||||
if (image == NULL || path == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
@ -730,6 +954,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 +974,225 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *iso_tree_get_node_path(IsoNode *node)
|
||||
{
|
||||
char *path = NULL, *parent_path = NULL;
|
||||
|
||||
if (node == NULL || node->parent == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((IsoNode*)node->parent == node) {
|
||||
return strdup("/");
|
||||
} else {
|
||||
parent_path = iso_tree_get_node_path((IsoNode*)node->parent);
|
||||
if (parent_path == NULL)
|
||||
goto ex;
|
||||
if (strlen(parent_path) == 1) {
|
||||
path = calloc(1, strlen(node->name) + 2);
|
||||
if (path == NULL)
|
||||
goto ex;
|
||||
sprintf(path, "/%s", node->name);
|
||||
} else {
|
||||
path = calloc(1, strlen(parent_path) + strlen(node->name) + 2);
|
||||
if (path == NULL)
|
||||
goto ex;
|
||||
sprintf(path, "%s/%s", parent_path, node->name);
|
||||
}
|
||||
}
|
||||
ex:;
|
||||
if (parent_path != NULL)
|
||||
free(parent_path);
|
||||
return path;
|
||||
}
|
||||
|
||||
/* ------------------------- tree cloning ------------------------------ */
|
||||
|
||||
static
|
||||
int iso_tree_copy_node_attr(IsoNode *old_node, IsoNode *new_node, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
new_node->mode = old_node->mode;
|
||||
new_node->uid = old_node->uid;
|
||||
new_node->gid = old_node->gid;
|
||||
new_node->atime = old_node->atime;
|
||||
new_node->mtime = old_node->mtime;
|
||||
new_node->ctime = old_node->ctime;
|
||||
new_node->hidden = old_node->hidden;
|
||||
ret = iso_node_clone_xinfo(old_node, new_node, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
@param flag bit0= merge directory with *new_node
|
||||
*/
|
||||
static
|
||||
int iso_tree_clone_dir(IsoDir *old_dir,
|
||||
IsoDir *new_parent, char *new_name, IsoNode **new_node,
|
||||
int flag)
|
||||
{
|
||||
IsoDir *new_dir = NULL;
|
||||
IsoNode *sub_node = NULL, *new_sub_node = NULL;
|
||||
IsoDirIter *iter = NULL;
|
||||
int ret;
|
||||
|
||||
if (flag & 1) {
|
||||
new_dir = (IsoDir *) *new_node;
|
||||
} else {
|
||||
*new_node = NULL;
|
||||
ret = iso_tree_add_new_dir(new_parent, new_name, &new_dir);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
/* Avoid traversal of target directory to allow cloning of old_dir to a
|
||||
subordinate of old_dir.
|
||||
*/
|
||||
iso_node_take((IsoNode *) new_dir);
|
||||
|
||||
ret = iso_dir_get_children(old_dir, &iter);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
while(1) {
|
||||
ret = iso_dir_iter_next(iter, &sub_node);
|
||||
if (ret == 0)
|
||||
break;
|
||||
ret = iso_tree_clone(sub_node, new_dir, sub_node->name, &new_sub_node,
|
||||
flag & 1);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* Now graft in the new tree resp. graft back the merged tree */
|
||||
ret = iso_dir_add_node(new_parent, (IsoNode *) new_dir, 0);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
|
||||
if (!(flag & 1))
|
||||
*new_node = (IsoNode *) new_dir;
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (iter != NULL)
|
||||
iso_dir_iter_free(iter);
|
||||
if (ret < 0 && new_dir != NULL) {
|
||||
if (flag & 1) {
|
||||
/* graft back the merged tree (eventually with half copy) */
|
||||
iso_dir_add_node(new_parent, (IsoNode *) new_dir, 0);
|
||||
} else {
|
||||
iso_node_remove_tree((IsoNode *) new_dir, NULL);
|
||||
*new_node = NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int iso_tree_clone_file(IsoFile *old_file,
|
||||
IsoDir *new_parent, char *new_name, IsoNode **new_node,
|
||||
int flag)
|
||||
{
|
||||
IsoStream *new_stream = NULL;
|
||||
IsoFile *new_file = NULL;
|
||||
int ret;
|
||||
|
||||
*new_node = NULL;
|
||||
|
||||
ret = iso_stream_clone(old_file->stream, &new_stream, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iso_tree_add_new_file(new_parent, new_name, new_stream, &new_file);
|
||||
if (ret < 0)
|
||||
goto ex;
|
||||
new_stream = NULL; /* now owned by new_file */
|
||||
new_file->sort_weight = old_file->sort_weight;
|
||||
*new_node = (IsoNode *) new_file;
|
||||
ret = ISO_SUCCESS;
|
||||
ex:;
|
||||
if (new_stream != NULL)
|
||||
iso_stream_unref(new_stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int iso_tree_clone_symlink(IsoSymlink *node,
|
||||
IsoDir *new_parent, char *new_name, IsoNode **new_node,
|
||||
int flag)
|
||||
{
|
||||
IsoSymlink *new_sym;
|
||||
int ret;
|
||||
|
||||
*new_node = NULL;
|
||||
|
||||
ret = iso_tree_add_new_symlink(new_parent, new_name, node->dest, &new_sym);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
new_sym->fs_id = node->fs_id;
|
||||
new_sym->st_dev = node->st_dev;
|
||||
new_sym->st_ino = node->st_ino;
|
||||
*new_node = (IsoNode *) new_sym;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
int iso_tree_clone_special(IsoSpecial *node,
|
||||
IsoDir *new_parent, char *new_name, IsoNode **new_node,
|
||||
int flag)
|
||||
{
|
||||
IsoSpecial *new_spec;
|
||||
IsoNode *iso_node;
|
||||
int ret;
|
||||
|
||||
iso_node = (IsoNode *) node;
|
||||
ret = iso_tree_add_new_special(new_parent, new_name, iso_node->mode,
|
||||
node->dev, &new_spec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
new_spec->fs_id = node->fs_id;
|
||||
new_spec->st_dev = node->st_dev;
|
||||
new_spec->st_ino = node->st_ino;
|
||||
*new_node = (IsoNode *) new_spec;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/* API */
|
||||
int iso_tree_clone(IsoNode *node,
|
||||
IsoDir *new_parent, char *new_name, IsoNode **new_node,
|
||||
int flag)
|
||||
{
|
||||
int ret = ISO_SUCCESS;
|
||||
|
||||
if (iso_dir_get_node(new_parent, new_name, new_node) == 1) {
|
||||
if (! (node->type == LIBISO_DIR && (*new_node)->type == LIBISO_DIR &&
|
||||
(flag & 1))) {
|
||||
*new_node = NULL;
|
||||
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||
}
|
||||
} else
|
||||
flag &= ~1;
|
||||
|
||||
if (node->type == LIBISO_DIR) {
|
||||
ret = iso_tree_clone_dir((IsoDir *) node, new_parent, new_name,
|
||||
new_node, flag & 1);
|
||||
} else if (node->type == LIBISO_FILE) {
|
||||
ret = iso_tree_clone_file((IsoFile *) node, new_parent, new_name,
|
||||
new_node, 0);
|
||||
} else if (node->type == LIBISO_SYMLINK) {
|
||||
ret = iso_tree_clone_symlink((IsoSymlink *) node, new_parent, new_name,
|
||||
new_node, 0);
|
||||
} else if (node->type == LIBISO_SPECIAL) {
|
||||
ret = iso_tree_clone_special((IsoSpecial *) node, new_parent, new_name,
|
||||
new_node, 0);
|
||||
} else if (node->type == LIBISO_BOOT) {
|
||||
ret = ISO_SUCCESS; /* API says they are silently ignored */
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (flag & 1)
|
||||
return 2; /* merged two directories, *new_node is not new */
|
||||
ret = iso_tree_copy_node_attr(node, *new_node, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_IMAGE_TREE_H_
|
||||
#define LIBISO_IMAGE_TREE_H_
|
||||
|
877
libisofs/util.c
877
libisofs/util.c
File diff suppressed because it is too large
Load Diff
142
libisofs/util.h
142
libisofs/util.h
@ -1,15 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_UTIL_H_
|
||||
#define LIBISO_UTIL_H_
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifndef MAX
|
||||
@ -25,6 +34,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.
|
||||
*
|
||||
@ -139,16 +153,19 @@ char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot);
|
||||
|
||||
/**
|
||||
* Create a Joliet file identifier that consists of name and extension. The
|
||||
* combined name and extension length will not exceed 128 bytes, and the
|
||||
* name and extension will be separated (.). All characters consist of
|
||||
* 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL.
|
||||
* combined name and extension length will normally not exceed 64 characters
|
||||
* (= 128 bytes). The name and the extension will be separated (.).
|
||||
* All characters consist of 2 bytes and the resulting string is
|
||||
* NULL-terminated by a 2-byte NULL.
|
||||
*
|
||||
* Note that version number and (;1) is not appended.
|
||||
*
|
||||
* @param flag
|
||||
* bit0= no_force_dots
|
||||
* bit1= allow 103 characters rather than 64
|
||||
* @return
|
||||
* NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
uint16_t *iso_j_file_id(const uint16_t *src);
|
||||
uint16_t *iso_j_file_id(const uint16_t *src, int flag);
|
||||
|
||||
/**
|
||||
* Create a Joliet directory identifier that consists of name and optionally
|
||||
@ -156,10 +173,12 @@ uint16_t *iso_j_file_id(const uint16_t *src);
|
||||
* and the name and extension will be separated (.). All characters consist of
|
||||
* 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL.
|
||||
*
|
||||
* @param flag
|
||||
* bit1= allow 103 characters rather than 64
|
||||
* @return
|
||||
* NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
uint16_t *iso_j_dir_id(const uint16_t *src);
|
||||
uint16_t *iso_j_dir_id(const uint16_t *src, int flag);
|
||||
|
||||
/**
|
||||
* Like strlen, but for Joliet strings.
|
||||
@ -245,7 +264,14 @@ int iso_eaccess(const char *path);
|
||||
* Copy up to \p len chars from \p buf and return this newly allocated
|
||||
* string. The new string is null-terminated.
|
||||
*/
|
||||
char *strcopy(const char *buf, size_t len);
|
||||
char *iso_util_strcopy(const char *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Copy up to \p len chars from \p buf and return this newly allocated
|
||||
* string. The new string is null-terminated.
|
||||
* Any trailing blanks will be removed.
|
||||
*/
|
||||
char *iso_util_strcopy_untail(const char *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Copy up to \p max characters from \p src to \p dest. If \p src has less than
|
||||
@ -435,4 +461,102 @@ void iso_htable_destroy(IsoHTable *table, hfree_data_t free_data);
|
||||
*/
|
||||
unsigned int iso_str_hash(const void *key);
|
||||
|
||||
/**
|
||||
* Encode an integer as LEN,BYTES for being a component in certain AAIP
|
||||
* attribute values.
|
||||
*/
|
||||
int iso_util_encode_len_bytes(uint32_t data, char *buffer, int data_len,
|
||||
int *result_len, int flag);
|
||||
|
||||
/**
|
||||
* Decode an integer as LEN,BYTES for being a component in certain AAIP
|
||||
* attribute values.
|
||||
* @param data returns the decoded value
|
||||
* @param buffer contains the encoded value
|
||||
* @param data_len returns the number of value bytes (without len byte)
|
||||
* @param buffer_len tells the number of valid buffer bytes
|
||||
*/
|
||||
int iso_util_decode_len_bytes(uint32_t *data, char *buffer, int *data_len,
|
||||
int buffer_len, int flag);
|
||||
|
||||
|
||||
/* Evaluate a data block whether it is a libisofs session checksum tag of
|
||||
desired type and eventually use it to verify the MD5 checksum computed
|
||||
so far.
|
||||
@param block The data block to be evaluated
|
||||
@param desired Bit map which tells what tag types are expected
|
||||
(0 to 30)
|
||||
@param lba The address from where block was read
|
||||
@param ctx The checksum context computed so far
|
||||
@param ctx_start_lba The block address where checksum computing started
|
||||
@param tag_type Returns the tag type (0 means invalid tag type)
|
||||
@param flag Bitfield for control purposes, unused yet, submit 0
|
||||
@return 1= tag is desired and matches
|
||||
0= not a recognizable tag or a undesired tag
|
||||
<0 is error or mismatch
|
||||
*/
|
||||
int iso_util_eval_md5_tag(char *block, int desired, uint32_t lba,
|
||||
void *ctx, uint32_t ctx_start_lba,
|
||||
int *tag_type, uint32_t *next_tag, int flag);
|
||||
|
||||
|
||||
int iso_util_tag_magic(int tag_type, char **tag_magic, int *len, int flag);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* In md5.h these function prototypes would be neighbors of (Ecma119Image *)
|
||||
which needs inclusion of ecma119.h and more. So, being generic, they ended
|
||||
up here.
|
||||
*/
|
||||
|
||||
/* Function to identify and manage md5sum indice of the old image.
|
||||
* data is supposed to be a 4 byte integer, bit 31 shall be 0,
|
||||
* value 0 of this integer means that it is not a valid index.
|
||||
*/
|
||||
int checksum_cx_xinfo_func(void *data, int flag);
|
||||
|
||||
/* The iso_node_xinfo_cloner function which gets associated to
|
||||
* checksum_cx_xinfo_func by iso_init() resp. iso_init_with_flag() via
|
||||
* iso_node_xinfo_make_clonable()
|
||||
*/
|
||||
int checksum_cx_xinfo_cloner(void *old_data, void **new_data, int flag);
|
||||
|
||||
|
||||
/* Function to identify and manage md5 sums of unspecified providence stored
|
||||
* directly in this xinfo. This is supposed to override any other recorded
|
||||
* MD5 of the node unless data get copied and checksummed during that copying.
|
||||
*/
|
||||
int checksum_md5_xinfo_func(void *data, int flag);
|
||||
|
||||
/* The iso_node_xinfo_cloner function which gets associated to
|
||||
* checksum_md5_xinfo_func by iso_init() resp. iso_init_with_flag() via
|
||||
* iso_node_xinfo_make_clonable()
|
||||
*/
|
||||
int checksum_md5_xinfo_cloner(void *old_data, void **new_data, int flag);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
void *iso_alloc_mem(size_t size, size_t count, int flag);
|
||||
|
||||
#define LIBISO_ALLOC_MEM(pt, typ, count) { \
|
||||
pt= (typ *) iso_alloc_mem(sizeof(typ), (size_t) (count), 0); \
|
||||
if(pt == NULL) { \
|
||||
ret= ISO_OUT_OF_MEM; goto ex; \
|
||||
} }
|
||||
|
||||
#define LIBISO_ALLOC_MEM_VOID(pt, typ, count) { \
|
||||
pt= (typ *) iso_alloc_mem(sizeof(typ), (size_t) (count), 0); \
|
||||
if(pt == NULL) { \
|
||||
goto ex; \
|
||||
} }
|
||||
|
||||
#define LIBISO_FREE_MEM(pt) { \
|
||||
if(pt != NULL) \
|
||||
free((char *) pt); \
|
||||
}
|
||||
|
||||
|
||||
#endif /*LIBISO_UTIL_H_*/
|
||||
|
@ -2,10 +2,15 @@
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "libisofs.h"
|
||||
|
||||
|
@ -2,10 +2,15 @@
|
||||
* 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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "libisofs.h"
|
||||
|
||||
@ -159,7 +164,7 @@ int iso_rbtree_insert(IsoRBTree *tree, void *data, void **item)
|
||||
new = data;
|
||||
added = 1;
|
||||
} else {
|
||||
struct iso_rbnode head = { 0 }; /* False tree root */
|
||||
struct iso_rbnode head = { 0, {NULL, NULL}, 0 }; /* False tree root */
|
||||
|
||||
struct iso_rbnode *g, *t; /* Grandparent & parent */
|
||||
struct iso_rbnode *p, *q; /* Iterator & parent */
|
||||
@ -198,7 +203,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) {
|
||||
@ -276,7 +285,7 @@ void ** iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
||||
size_t *size)
|
||||
{
|
||||
size_t pos;
|
||||
void **array;
|
||||
void **array, **new_array;
|
||||
|
||||
array = malloc((tree->size + 1) * sizeof(void*));
|
||||
if (array == NULL) {
|
||||
@ -287,7 +296,12 @@ void ** iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
||||
pos = rbtree_to_array_aux(tree->root, array, 0, include_item);
|
||||
array[pos] = NULL;
|
||||
|
||||
array = realloc(array, (pos + 1) * sizeof(void*));
|
||||
new_array = realloc(array, (pos + 1) * sizeof(void*));
|
||||
if (new_array == NULL) {
|
||||
free((char *) array);
|
||||
return NULL;
|
||||
}
|
||||
array= new_array;
|
||||
if (size) {
|
||||
*size = pos;
|
||||
}
|
||||
|
@ -2,8 +2,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
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
* modify it under the terms of the GNU General Public License version 2
|
||||
* or later as published by the Free Software Foundation.
|
||||
* See COPYING file for details.
|
||||
*/
|
||||
#ifndef LIBISO_IMAGE_WRITER_H_
|
||||
#define LIBISO_IMAGE_WRITER_H_
|
||||
|
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