Compare commits

...

268 Commits

Author SHA1 Message Date
1d44d931d0 Version leap to 0.6.20 2009-05-30 21:24:50 +02:00
5d5a0cbfd4 Removed change timestamps of 0.6.19 2009-05-30 18:00:21 +02:00
4353a35c59 Removed some development remarks 2009-05-30 16:36:54 +02:00
2f48297d25 Removed loud warning not to activate Libisofs_hardlink_matcheR 2009-05-28 13:25:21 +02:00
dfcb815480 Removed experimental code about inode number generation from LBA.
Obsoleted macros Libisofs_ino_from_lbA Libisofs_patch_ticket_144.
2009-05-26 18:47:23 +02:00
f370829717 Removed old code for AAIP 1.0 production.
Obsoleted macro Libisofs_aaip_2_0.
2009-05-26 18:41:51 +02:00
ef96f3588c Made use of iconv wrapper function unconditionally.
Obsoleted macro Libisofs_with_iso_iconV.
2009-05-26 18:23:59 +02:00
e8fc149423 Made centralized call of setlocale() unconditional.
Obsoleted macro Libisofs_setlocale_in_iniT.
2009-05-26 18:13:15 +02:00
e12d409b80 Made sure that IsoStream from old image are equivalent only if their
data extents have same LBAs and sizes.
2009-05-24 18:22:02 +02:00
b34fd35e62 Fixed bugs in iso_node_cmp_flag() introduced with revision 559
and clarified constraints for stream comparison functions in libisofs.h
2009-05-18 15:33:36 +02:00
714ee67472 New API call iso_node_cmp_ino()
and a bug fix about IsoSpecial and IsoSymlink in iso_node_cmp_flag()
2009-05-16 18:50:23 +02:00
8c4682ae92 IsoStream version 3 with cmp_ino(),
new API call iso_stream_cmp_ino() for proper comparison of filtered streams
2009-05-12 09:29:06 +02:00
5b073a2f29 New API call iso_write_opts_set_hardlinks() controls hardlink matching,
new API call iso_write_opts_set_rrip_1_10_px_ino() controls RRIP-1.10 PX size.
2009-05-09 20:45:14 +02:00
c6f1101e9d Fixed a severe inode number mash-up from revision 554
and a minor bug introduced with revision 547 (for ticket 147).
2009-05-06 16:18:45 +02:00
f8d3bca20a Registering fs,dev,ino of nodes which stem from outside the imported image
and using fs,dev,ino of IsoSymlink and IsoSpecial.
2009-05-05 22:03:44 +02:00
46a947b602 Created means to inquire ECMA119_SYMLINK and ECMA119_SPECIAL
for their original fs,dev,ino
2009-05-03 19:21:21 +02:00
56796ff55f Introduced hardlink unification at image generation time.
For now it works only with data files or with files from the imported image.
2009-05-03 17:08:29 +02:00
1cbae01f12 Outsourced stream comparison from iso_file_src_cmp() to iso_stream_cmp_ino() 2009-05-03 08:42:45 +02:00
da4634a593 Removed a redundant test expression 2009-05-02 19:57:39 +02:00
f18d5157dc Caused image root to memorize its eventual PX inode number. 2009-05-01 16:18:59 +02:00
1195614881 Removed a redundant line of code 2009-05-01 15:02:30 +02:00
1218e6e32d New API call iso_read_opts_set_new_inos() 2009-05-01 15:00:43 +02:00
95381ce258 Made directory inodes persistent during multi-session.
The reason is to produce a continued ino history for eventual incremental
backups from ISO images.
2009-05-01 12:49:37 +02:00
19fd87ef7b Small adjustments in new code after review. 2009-04-29 12:52:32 +02:00
d20da80767 Transfering inode numbers from PX entries to IsoNode during image import
and using these numbers in PX entries during next image generation.
This also answers the concerns about PX without ino in RRIP 1.12
and PX with ino in RRIP 1.10 images produced by mkisofs.
2009-04-28 22:40:15 +02:00
5009d1038d Made early preparations for implementation of hard link persistence 2009-04-26 12:57:17 +02:00
1ae2a39d1d Registered stream types "gzip" and "pizg" 2009-04-24 08:45:03 +02:00
70af4872c9 Clarification of iso_stream_get_source_path() result 2009-04-19 07:10:22 +02:00
71d491ed37 Version leap to 0.6.19 2009-04-17 14:35:30 +02:00
cad3b000cf Forgot to change the doc file names in EXTRA_DIST of Makefile.am 2009-04-16 09:27:36 +02:00
ece42746ec Version leap to 0.6.18 2009-04-15 20:50:34 +02:00
3f90111052 Removed change timestamps of 0.6.17 2009-04-15 16:50:44 +02:00
d87e5721db Removed some development remarks
and implemented skipping of zisofs headers larger than 16 bytes.
2009-04-15 13:22:20 +02:00
00802a1934 New API functions iso_file_add_gzip_filter() and iso_gzip_get_refcounts(). 2009-04-14 22:26:00 +02:00
c2f502b9a8 Silenced a compiler warning with zisofs filter 2009-04-14 11:48:41 +02:00
1f2fd259ae New API call int iso_node_zf_by_magic() for marking pre-compressed data
file nodes which were originally produced by program mkzftree.
2009-04-13 20:51:38 +02:00
9a873ed693 Fixed a bug with non-appending multi-session and zisofs decompression. 2009-04-12 16:21:46 +02:00
ec672ab903 Making sure that ZF fields get appropriately carried on with multi-session
even if osiz filters have been removed.
2009-04-12 13:13:04 +02:00
99ddd5c116 New API functions iso_zisofs_set_params(), iso_zisofs_get_params() 2009-04-11 19:10:37 +02:00
63ddfc1c94 Global reference counters for both zisofs filter types and
new API function iso_zisofs_get_refcounts()
2009-04-11 15:25:40 +02:00
6886777ea0 Installing a zisofs uncompression filter on file from ISO image which bear
a ZF entry. Storing ZF entries during image write if that filter is found
directly on a fsrc stream from the loaded image and content does not get
copied.
2009-04-11 14:15:34 +02:00
77591e4546 Using faster compression level
and fixed a bug with uncompression if the last block is all zero.
2009-04-11 07:49:20 +02:00
540df15ec9 Writing ZF entries if filters and image generation mode indicate so. 2009-04-10 22:38:16 +02:00
ce7a5c810f Implemented a zisofs uncompression filter. 2009-04-10 12:16:41 +02:00
a809a87eef New API call iso_file_add_zisofs_filter() (needs -lz and <zlib.h>).
This does not produce ZF entries yet but filtered file content already
suits mkzftree -uF
2009-04-09 16:18:50 +02:00
5732726a27 Some polishing of zisofs documentation. 2009-04-08 09:52:10 +02:00
aae169aeeb Documented the zisofs format by H. Peter Anvin. 2009-04-08 09:10:47 +02:00
1b5328d619 Corrected a remnant "AA" in AAIP specs. 2009-04-07 18:11:30 +02:00
d565ae87f4 Removed dangerous test code of Libisofs_file_src_cmp_non_zerO. 2009-04-07 12:21:35 +02:00
98a6db7f7f Made comparison of file sizes in iso_file_src_cmp() unconditional. 2009-04-07 12:17:52 +02:00
8a0be8ca19 Corrected test of Libisofs_setlocale_in_iniT. 2009-04-07 12:13:22 +02:00
dd1cde0379 Made portability improvement Libisofs_avoid_using_allocA unconditional. 2009-04-07 12:07:48 +02:00
d8d2709de9 Made bug fix Libisofs_rrip_1_10_er_bugfiX unconditional 2009-04-07 11:52:03 +02:00
854a3b8088 Made bug fix Libisofs_external_filters_selecT unconditional 2009-04-07 11:45:17 +02:00
e8f8876ee6 New API function iso_stream_get_source_path() tries to obtain a source
path depending on the stream class.
2009-04-06 14:19:49 +02:00
f709a95fda Some documentation polishing in libisofs.h 2009-04-06 12:25:55 +02:00
d98081f173 (Forgot to store libisofs.h before rev 514) 2009-04-06 09:56:26 +02:00
6389bbbf58 Changed freshly introduced iso_file_get_external_filter()
to iso_stream_get_external_filter().
2009-04-06 09:52:21 +02:00
b27bcc7022 Experiment about select() versus non-blocking i/o. select() lost. 2009-04-05 14:48:03 +02:00
f2b7872fc6 Fixed a bug about detection of failure inside iso_file_add_external_filter() 2009-04-05 12:29:37 +02:00
da125e8f6b Changed sequence of fork and stream opening in extf_stream_class.open().
So the child does not inherit the pipe inlets of underlying filters
which would stay open and prevent those underlying filter children
from seeing EOF at their input.
2009-04-05 09:56:12 +02:00
198f6536bc New API call iso_node_lookup_attr()
and new xattr "isofs.st" for image start timestamp.
2009-04-03 15:34:23 +02:00
437713cd8e Moved storage location of suffix from xorriso into IsoExternalFilterCommand 2009-04-02 18:07:27 +02:00
0a265d9d4f Changed IsoExternalFilterCommand.behavior bit0.
The filter does not get installed if input size is 0.
This resembles more the other behavior bits.
2009-04-02 09:14:21 +02:00
806ea7b82e New component IsoExternalFilterCommand.name 2009-04-01 17:53:41 +02:00
e7853df2f4 Changed some documentation references from AAIP-1.0 to AAIP-2.0. 2009-03-31 13:00:33 +02:00
ece52dc070 Fixed a false success return value with iso_aa_lookup_attr(). 2009-03-31 12:16:19 +02:00
21de3e2087 Switched from AAIP-1.0 with field "AA" to AAIP-2.0 with field "AL"
because ancient Apple ISO 9660 already used "AA".
Old AAIP-1.0 enhanced images can still be read and luckily their AAIP fields
can be distinguished from eventual Apple AA fields.
2009-03-31 11:40:58 +02:00
d28351c5a4 Adjustment of minimal size for a IsoExternalFilterCommand.behavior bit2 filter 2009-03-29 18:45:00 +02:00
2534be5b5d Implemented IsoExternalFilterCommand.behavior bits 1 and 2
which control revocation due to insufficient size reduction.
2009-03-29 14:37:26 +02:00
681d092118 New IsoStream_Iface.version 2 with method .get_input_stream(),
new API function iso_stream_get_input_stream(),
new API function iso_file_remove_filter(),
iso_file_get_old_image_sections() now refers to the most original stream
of a file.
2009-03-28 19:37:44 +01:00
8b0920df53 Fixed a bug which prevented final waiting and caused lots of zombies 2009-03-27 21:25:44 +01:00
e759bd5240 mall adjustment in API description 2009-03-27 18:15:18 +01:00
1a307cb790 Introduced IsoExternalFilterCommand.behavior and implemented
optional shortcut with files of size 0.
2009-03-27 16:40:07 +01:00
41f75ea21f Fixed a SIGSEGV in iso_file_get_old_image_sections() with a
IsoFile from the old session which has not FSrcStreamData 
attached to its IsoStream.
2009-03-27 14:43:43 +01:00
6cf484442c Fixed a gridlock of external filtering in case that the
filter program is slow with processing.
2009-03-27 13:44:29 +01:00
691887fd2c New API function iso_file_add_external_filter()
with public parameter class IsoExternalFilterCommand
allows to use child processes as external content filter for IsoFile objects.
2009-03-26 17:34:38 +01:00
6f9db3d8c1 Introduced short notations for AAIP namespaces "trusted." and "security." 2009-03-22 11:15:05 +01:00
8eff065b5f Fixed wrong use of acl_free() 2009-03-21 22:59:06 +01:00
5f2bde776b Closed memory leaks opened with rev 487. 2009-03-21 11:09:14 +01:00
0402325ec2 New API call iso_read_opts_auto_input_charset() allows to obtain
the image tree character set name from root xattr "isofs.cs".
2009-03-20 17:48:42 +01:00
da2619c42a New API function iso_init_with_flag().
Moved setup of locale from various places to util.c:iso_init_locale().
It is now called by the iso_init*() functions only.
2009-03-19 12:56:25 +01:00
183ed6cc5a Made read_aaip_AA() safe against eventual Apple ISO AA fields 2009-03-18 10:27:28 +01:00
cd427b269a Get on FreeBSD pkgconfigdir=.../libdata , on Linux and others: .../lib 2009-03-17 21:33:20 +01:00
50edfbea51 Avoided use of function alloca() by macro Libisofs_avoid_using_allocA
and incremented version to 0.6.17
2009-03-17 21:25:43 +01:00
a6090a6273 Version leap to 0.6.16 2009-03-10 16:45:37 +01:00
a87c28da95 Made sorting order under Libisofs_file_src_cmp_sizE identical to
old sorting order. Just in case it matters.
(Is there any reason for the inverse order of dev_id ?)
2009-03-10 15:34:09 +01:00
4d0063f7e2 Bug fix: ECMA-119 ".." pointed always to the same block as ".".
Bug fix: iso_write_opts_set_rrip_version_1_10() caused wrong size of
         root record CE,
Stability enhancement: util.c:str2ascii() got a fallback for the case
                       that charset "WCHAR_T" is not available,
Debugging wrapper around iconv*() calls,
Experiments about inode numbers in fs_image,
Experiment to insert obsolete RR entries.
(Sorry for the obfuscation. Most is due to a hard ride on Solaris.
 See macros at the end of libisofs/libisofs.h)
2009-03-10 14:32:05 +01:00
4f468171ad Experiments about inode number generation for nodes out of the loaded
image.
2009-03-07 08:28:35 +01:00
32dc6dd041 Lifted the ban on operating systems other than Linux and FreeBSD 2009-03-05 20:13:14 +01:00
8d8dcb9c93 Changed severity of ISO_FILENAME_WRONG_CHARSET from HINT to WARNING.
Keeping old error code as ISO_FILENAME_WRONG_CHARSET_OLD.
2009-03-03 16:47:53 +01:00
e1460aa9a6 Version leap to 0.6.15 and
new API call iso_write_opts_get_data_start()
2009-02-28 23:22:31 +01:00
4daf626493 Made root node write and read own AA entries. 2009-02-24 17:50:53 +01:00
356b73eda8 Makefile.am still included outdated susp_aaip_0_2.txt
rather than susp_aaip_1_0.txt
2009-02-21 12:53:55 +01:00
f52c1aeb77 Version leap to 0.6.14 2009-02-19 17:02:29 +01:00
97d885fc9a Made AAIP 1.0 official, mentioned it in aaip source files,
and claimed copyright and GPLv2 on aaip source files.
2009-02-19 09:36:22 +01:00
0e0ecc1d00 Made code branch of Libisofs_with_aaiP unconditional
and removed change marks by (co-)copyright claims.
2009-02-18 23:01:14 +01:00
c1ba7d93d9 Removed dependencies of libburn where possible and removed
the remaining demo/iso_grow.c from Makefile.am.
2009-02-18 10:29:26 +01:00
a097793caf Registered first name of namespace isofs: isofs.di 2009-02-17 19:40:28 +01:00
e17a8c718f Fixed a memory leak underneath iso_node_get_attrs() 2009-02-17 15:40:00 +01:00
fb2309ea16 Moved iso_local_*() API functions from node.c to fs_local.c 2009-02-16 08:29:21 +01:00
e45f41fb44 Removed obsolete macro Libisofs_with_aaiP_retro and its unsuitable
code branches.
"AAIP_0100" gets issued if macro Libisofs_aaip_1_0 is defined.
2009-02-14 12:10:02 +01:00
0ada61b15e Gave up macro Libisofs_new_nm_sl_cE and the old computation of NM, SL, AA size. 2009-02-14 11:14:27 +01:00
c789c23119 Removed clearly obsolete code branches. 2009-02-14 11:05:33 +01:00
49821f6962 Made preservation of ACL in iso_node_set_attrs() more efficient 2009-02-13 20:05:42 +01:00
22e45ed489 Preserving non-userspace xattr if all userspace shall be overwritten. 2009-02-13 18:45:53 +01:00
1b3f5186e7 Revoked AAIP prescription to map reserved name start bytes into "user."
name space. (It made trouble with cyclic conversions.)
2009-02-11 08:30:37 +01:00
620547ac0a Recognizing future AAIP signature "AAIP_0100" 2009-02-10 21:02:58 +01:00
699866f984 Introduced into AAIP a short notation for name spaces "system.", "user.",
and "isofs.".
2009-02-10 20:36:34 +01:00
2633aab967 Fixed memory hog in read_aaip_AA().
todo: Find the reason why node xinfo is not freed when the image is discarded.
This helped the hog to survive undetected since January 14.
2009-02-09 17:46:35 +01:00
b09dcd5246 Fixed a bug about setting "default" ACL on Linux directories. 2009-02-09 11:17:33 +01:00
b1f8161006 Correct group permission bits with iso_read_opts_set_no_aaip(,1)
and node import from image with ACLs.
2009-02-08 12:45:15 +01:00
d7f691d6df Correct group permission bits with -acl off and import of disk file with ACL.
New API function iso_local_get_perms_wo_acl().
2009-02-07 21:00:43 +01:00
b5fd981482 Changing S_IRWXG from "mask::" to "group::" settings when
a non-trivial ACL gets erased. New API call iso_node_get_perms_wo_acl()
allows to obtain st_mode prediction for ACL removal.
Still to do: handle ACL stripping with st_mode import from local filesystem
and st_mode import from ISO image.
2009-02-07 09:48:30 +01:00
c974365b16 Extended the capabilities of iso_node_set_attrs() and
mentioned the new error codes in the error text generator
2009-02-06 11:41:24 +01:00
f66e3b8e2f Checking for iconv(3) in separate libiconv
(this can happen on FreeBSD)
2009-02-04 20:57:20 +01:00
64a9b79224 Some comment changes which were not stored before the previous commit 2009-02-04 20:16:32 +01:00
e8267b71d1 Took into respect that ACL operations always happen on link targets
while xattr can happen on the link itself.
2009-02-04 19:53:00 +01:00
1add3e32c5 Revoked the iconv dummy of previous revision
Solution was:
  export CPPFLAGS="-I/usr/local/include"
  export LDFLAGS="-L/usr/local/lib -liconv"
  ./configure
2009-02-03 21:39:54 +01:00
4c13522783 Some adpations to FreeBSD
and a temporary dummy of iconv (which is not installed on the test box)
2009-02-03 16:13:08 +01:00
8d459c7f77 Fixed unterminated comment. 2009-02-02 21:33:22 +01:00
1eb8029e60 Some enhancements about xattr API. 2009-02-02 21:10:21 +01:00
4950f869cb Giving access to AAIP xattr by new API functions iso_node_get_attrs() and
iso_node_set_attrs. Giving access to local filesystem xattr by new API
functions iso_local_get_attrs(), iso_local_set_attrs().
2009-02-02 11:49:28 +01:00
c226491f18 Polished AAIP specs. 2009-01-31 10:25:04 +01:00
84c100c2f5 Gave up adjustability of Signature Word "AA" in specs and implementation. 2009-01-30 18:58:11 +01:00
b600757649 Changed iso_node_set_acl_text() and iso_node_set_acl_text() so they
process both eventual ACLs of a node in one call.
2009-01-30 15:37:48 +01:00
313c4ff20f Silenced a warning of FreeBSD about shifting 32-bit dev_t by 32 bit.
Silenced warnings of FreeBSD about unused variables.
2009-01-29 21:54:24 +01:00
b824db94dc Clarified role of aaip_xinfo_func in libisofs API 2009-01-29 11:24:20 +01:00
9f60c75f08 Introduced generic ACL-EA-system adapter aaip-os-dummy.c
which steps in at compile time if neither __FreeBSD__ nor __linux is defined.
2009-01-29 10:52:08 +01:00
6dee6e4c20 More bug fixes about "default" ACL.
Made aaip_xinfo_func() available unconditionally.
2009-01-28 12:37:59 +01:00
b53ef57ac6 New API call iso_local_get_acl_text()
and bug fixes about "default" ACL
2009-01-27 21:19:49 +01:00
0b4792bc0c Mentioned the need for 64 bit file i/o 2009-01-27 12:19:10 +01:00
2cc74562fb Changed aaip API to allow fabrication of missing mandatory ACL entries
from st_mode
2009-01-27 09:50:55 +01:00
d9f3244037 Updated AAIP specs by exlicit rules for ER and ES 2009-01-26 15:46:59 +01:00
4ed2269570 Writing ES fields with RRIP and AAIP fields when ER of AAIP is written.
Also provided API call iso_write_opts_set_aaip_susp_1_10() which prevents
writing AAIP ER and consequentially of ES fields.
2009-01-26 15:12:57 +01:00
7dfec561d9 Avoided to store deleted ACL as attribute with empty value 2009-01-25 10:49:07 +01:00
dc26d8eefc Updating st_mode permission bits in iso_node_set_acl_text() 2009-01-24 17:45:22 +01:00
bd9b49714f Let configure detect availability of libacl and of Linux listxattr call
and aaip-os work around eventual missing functionality
2009-01-23 18:28:51 +01:00
aae339fe49 voiding to store empty ACL for all directories withou ACL 2009-01-23 13:17:22 +01:00
c801fa60f7 Incremented version to 0.6.13 and .so age to 9. 2009-01-23 09:43:52 +01:00
c8495481ca Controlling import and export of ACL, EA, AAIP 2009-01-23 09:32:32 +01:00
65e5b00171 Disabled loading of AAIP from ISO images by default
and provided new API function iso_read_opts_set_no_aaip()
2009-01-21 16:03:59 +01:00
bb69e14b08 Better messages of non-AAIP aware libisofs about AAIP enhanced images 2009-01-21 14:25:08 +01:00
a5aedd51a4 Re-enabled compilation without Libisofs_with_aaiP
but prepared messages of that code for existence of AA and ER of AAIP
2009-01-21 14:08:10 +01:00
1150ee32a4 New API call iso_node_set_acl_text()
and automatic update of ACL entries by iso_node_set_permissions()
2009-01-21 13:29:10 +01:00
d4ce4a7f88 Forgot to store node.c before committing 425. 2009-01-19 10:52:40 +01:00
6659ec1566 Correcting my statement in the previous commit:
There is defined correspondence between ACL and st_mode in Linux man 5 acl.
It is complicated and libisofs will have to ensure integrity of ACL
manipulations and st_mode manipulations. (It will not check integrity when
loading ACLs and st_mode from filesystems.)
2009-01-19 10:48:34 +01:00
6ad6d3c219 Gave up deleting of single ACL entries if they match st_mode.
Only totally trivial ACLs are discarded as a whole.
This seems necessary because the relation between st_mode and ACL
is not clearly defined in man 5 acl.
2009-01-19 09:50:29 +01:00
24fadd7649 New API function iso_local_set_acl_text() 2009-01-18 22:36:06 +01:00
723d23321a Handling ACL entries which match the POSIX permissions 2009-01-18 18:39:06 +01:00
ece6eca9a5 Avoided memory overflow with Aaip_encode_debuG 2009-01-17 20:25:00 +01:00
20adf50275 New API function iso_node_get_acl_text
Fixes for problems with CE usage and reading of multiple AA fields
2009-01-17 16:06:05 +01:00
c6f4370e71 Fixed a memory hog about submitting multiple fields in aaip_add_AA() 2009-01-16 13:38:02 +01:00
d01b3cc6cc Implemented generation of AA strings from local filesystem
and upgraded IsoFileSourceIface lfs_class to version 1
2009-01-16 13:24:30 +01:00
9dc56426c0 New API call iso_file_source_get_aa_string()
and IsoFileSource_Iface.version == 1 with ifs_class
Now libisofs is able to load AA strings from images and to store them again.
2009-01-15 21:58:48 +01:00
de99f93640 Implemented reading of AA fields to struct image_fs_data.aa_string
and defined IsoFileSource_Iface version 1 with access function .get_aa_string()
2009-01-15 17:43:58 +01:00
3c91c2f333 Implemented reading of AA field string from iso_node_get_xinfo().
(No AA strings get submitted as xinfo yet.)
2009-01-14 15:49:02 +01:00
3294dd5e94 Introduced AAIP code. Now linking with libacl.
(Todo: handle system dependy of -lacl in configure.ac)
2009-01-14 12:11:47 +01:00
e8f1dfb8e5 Silenced warning about multiple ER fields. Enabled recognizing of AAIP-ER.
Vreixo needs to explain TODO #00016 in fs_image.c
2009-01-13 20:44:36 +01:00
19661b0c05 Testing the ER field which announces AAIP. 2009-01-13 20:25:12 +01:00
1267052c03 Accounting for the size of AA fields in rrip_calc_len() 2009-01-13 18:35:14 +01:00
f7a47baa22 Experiment with dummy AA fields.
Looks good when writing. But when reading there are
problems with the directory size which is not aligned
to 2048.
2009-01-13 14:02:27 +01:00
cc9de1507f Described license situation of make_isohybrid_mbr.c 2008-11-25 17:11:52 +01:00
6b273ef79a Added a missing change for RRIP-1.10 option to rrip_calc_len() 2008-11-25 17:07:24 +01:00
a8c7d1b0e6 Removed surplus line from rrip_add_PN().
It was introduced with the FreeBSD port.
2008-11-25 16:53:36 +01:00
7990e01a57 More apostrophes removed from messages 2008-11-25 16:49:10 +01:00
23e2647920 Described need to pad isohybrid to full MB.
Removed compiler warning about isohybrid FIXME.
2008-11-25 16:32:55 +01:00
412ad2fcdb Version switch to 0.6.12 , libisofs-6.8.0.so 2008-11-25 15:39:40 +01:00
14dd988f0f New API function iso_write_opts_set_dir_rec_mtime() to store the mtime
of the source files in their ECMA-119 Directory Records
2008-11-25 15:31:33 +01:00
698fdec290 New API function iso_write_opts_set_rrip_version_1_10() allows to
write old fashioned RRIP-1.10 rather than RRIP-1.12.
2008-11-25 15:19:53 +01:00
28e8936b4f Bug fix ticket 144: File size damage by non-unique inode numbers of
pre-RRIP 1.12 images

Replaced the extent-LBA based inode number by a static 32 bit counter.
I deem it safe because if the numbers repeat within a single image
reading, then we are doomed anyway. I banned inode number 0 just in
case it has a meaning.

TODO: what if ER says IEEE_1282 but the PX field has only 36 bytes ?
2008-11-25 14:34:47 +01:00
0026c93cd4 Emphasized in the API docs the fact that
iso_image_create_burn_source() starts image generation.
Mentioned the FreeBSD timezone bug with API docs of
iso_write_opts_set_always_gmt().
2008-11-25 13:26:34 +01:00
fcf22cffe7 Small changes for the FreeBSD port. 2008-11-25 12:49:44 +01:00
ed1041a069 Bug fix for ticket 145: ISOLINUX boot image does not get patched properly
Delayed the computation of El Torito until
all other computation methods were called.
This ensures that the LBA of isolinux.bin is
already computed when the patching gets defined.
The position of the El Torito writer in the list
was not changed. The call sequence of the write
methods was not changed.
2008-11-25 12:23:25 +01:00
eccaac09cc New API functions iso_set_local_charset() and iso_get_local_charset() 2008-11-25 12:13:51 +01:00
88ef351e74 Removed apostrophe from some error messages and
dangerous text display from character set conversion
error messages.
2008-11-25 12:05:03 +01:00
cb3a879baf Fix bug in make_isohybrid_mbr(). 2008-10-19 16:09:23 +02:00
7e97a45b20 Support for writing MBR in the system area, to make hybrid boot images.
With the specified isolinux option, a MBR is written to the system area, and this 
allows the image to boot from either CD/DVD or USB sticks.

This is also supported on overwriteable media (note that system area is always
overwritten), but it should not work on multisession media.
2008-10-19 16:03:13 +02:00
7db39f99b6 Add new API to deal with isolinux options.
This deprecates el_torito_patch_isolinux_image() in favour of the new API, that also
allows the generation of an hybrid boot image.
2008-10-19 16:00:51 +02:00
186c2f2ff7 Add Thomas function needed to make isohybrid bootable images. 2008-10-18 16:50:20 +02:00
1a4c5ba679 Increment version to 0.6.11 for next development cycle. 2008-10-18 16:49:21 +02:00
62315dfc44 I did more! 2008-10-06 08:44:14 +02:00
56287470b0 Preparing release 2008-10-06 08:39:04 +02:00
89b0e9da68 Patch isolinux image before image writing.
Currently isolinux images are patching on-the-fly during image writing, and
that can be a problem on multisession images, as we may be reading the
old image after begining the burning of the new session. That is not supported
in several media and lead to burning failure. Fixed by caching the patched
image on memory.
2008-09-29 22:33:26 +02:00
65252934de Fix SIGSEGV with El-Torito images. 2008-09-27 12:34:40 +02:00
60ab97b5f4 Increment version to 0.6.9 for next development cycle. 2008-09-20 21:14:36 +02:00
b959b150e9 Preparing a release 2008-09-18 07:09:05 +02:00
68419703d7 Added iso_image_update_sizes() API.
This requires increasing IsoStreamIface version, as we need to add a new 
method on it. API/ABI remains compatible with older version.
2008-09-07 16:32:18 +02:00
e79ee64a2f Fix bug #140, related to isolinux size, following patch by Christian Ostheimer.
We had assumed isolinux images are always a multiple of 4 bytes. However, 
this does not happens with recent isolinux images.
2008-08-29 20:54:14 +02:00
33e058a66a Fix bug #139 related to a wrong constant usage on non-emulated boot images. 2008-08-28 16:44:54 +02:00
75c44a1474 Merge Thomas Schmitt work that set 0.6.7 version and some error codes. 2008-08-26 16:51:30 +02:00
e91f12972b Switch to 0.6.7, error codes for iso_dat_source.read 2008-08-26 16:09:04 +02:00
c1a7702f52 Merge level3 branch, adding support for ISO-9660 Level 3. 2008-08-20 02:14:47 +02:00
37e6752375 Fix documentation related to valid error codes (see ticket #134). 2008-08-20 00:52:33 +02:00
1ccc532808 Improve messages shown on some errors (fixes ticket #137). 2008-08-20 00:40:20 +02:00
2de74d04a7 Fix severity of some errors (see ticket #137). 2008-08-20 00:40:11 +02:00
7a87f47542 Prevent negative priorities on wrong error codes (fixes bug #135). 2008-08-20 00:05:27 +02:00
690e02a461 Revert Mario workaround to deal with wrong error codes. 2008-08-19 22:28:18 +02:00
882073f145 Make ISO-9660 Level 3 be the default for Backup Write Profile. 2008-08-19 21:41:42 +02:00
fb3c3e1a6d Fix important bug. File sections must be computed before dir size. 2008-08-19 20:54:27 +02:00
ff480b35e9 Control size of extents with #define blocks, to help testing. 2008-08-19 19:44:47 +02:00
643dbef05c Store RR entries in Directory Record for each File Section.
Linux do not mount correctly images where RR entries are only stored in 
last File Section Directory Entry.
2008-08-19 03:46:41 +02:00
f9e15054db Correctly compute directoty size on Joliet and ISO-9660:1999 trees. 2008-08-19 03:46:04 +02:00
ce0949a585 Compute correctly directory size. 2008-08-19 03:31:50 +02:00
126e60741e Fix tiny memory leak. 2008-08-19 03:03:16 +02:00
2e99e1aac9 Add support for multisession on Level 3 images. 2008-08-19 02:45:20 +02:00
3a503a3e85 Implement iso_file_get_old_image_sections() and deprecate old way to obtain image lba. 2008-08-19 02:01:42 +02:00
87f08d27ac Add support for reading Level 3 images. 2008-08-19 01:08:46 +02:00
3f6da75e9c Only stored SUSP/RR entries in the directory entry for last extent. 2008-08-18 17:54:03 +02:00
6ff7699c47 Support for writting ISO Level 3 images.
This allows files greater than 4GB, that are written using multiple 
extents.
2008-08-17 21:59:48 +02:00
68bd636bd8 Document Multi-Extent feature. 2008-08-17 19:30:47 +02:00
35a623c7ec Some configure.ac changes 2008-06-01 14:19:55 +02:00
fc46f4ec84 Preparing 0.6.6 release 2008-06-01 14:19:02 +02:00
2cc8a6d978 Merged Vreixo branch 2008-06-01 10:41:52 +02:00
ab14c030bc Improve iso_write_opts_set_overwrite_buf() documentation.
Patch submitted by Thomas Schmitt.
2008-05-26 15:47:04 +02:00
86a3f4de22 Added iso_special_get_dev() API to retrieve devide id for device files. 2008-05-26 15:43:55 +02:00
558bdde116 Fix bug in read_rr_PN().
This caused device mino/major numbers to be read incorrectly from 
RockRidge PN entry.

Bug reported by Thomas Schmitt.
2008-05-26 10:48:25 +02:00
1756cf4c92 Fix a bug in iso_tree_path_to_node().
With paths where the last directory component is an existing 
non-directory in the ISO image and the leafname is any name it 
incorrectly returns 1 (node found).

Bug reported by Thomas Schmitt.
2008-05-26 10:46:28 +02:00
927fb62ac4 Yay 2008-04-27 21:43:30 +02:00
f8938bd37b Release! 2008-04-27 21:40:30 +02:00
2e0688dee6 Final NEWS update 2008-04-26 16:58:33 +02:00
e318d48cb9 Updated NEWS for release 2008-04-26 16:56:40 +02:00
84771aa83b Preparation for 0.6.4 release 2008-04-24 11:22:24 +02:00
7e617733b1 Implemented safety cap and did merge with vreixo branch 2008-04-22 22:24:00 +02:00
ccc7b0b58f Fix allocation problem. 2008-04-05 17:08:17 +02:00
b94d993239 Fixed licencing mishap in COPYRIGHT 2008-04-02 20:01:25 +02:00
7b0da1ecd6 Add a function to get the path of a node in the IsoImage. 2008-03-17 21:42:44 +01:00
2374976b6d Make iso_dir_find_children() work recursivelly. 2008-03-17 17:24:42 +01:00
8b10d3107a Make IsoDirIters take also a ref on the dir they iterate. 2008-03-17 16:02:50 +01:00
987fa4b323 Improve find iterator, to make has_next() actually work. 2008-03-17 15:50:38 +01:00
166f1d83bd Expose node extended info. Add unit test for it. 2008-03-15 17:34:58 +01:00
648941cb15 lseek() needs to be added to the end to ensure ABI compatibility. 2008-03-08 21:48:03 +01:00
d455f9b540 Add support for cut-out files. 2008-03-08 21:45:19 +01:00
bad03a9a2b Add lseek() function to IsoFileSource. 2008-03-08 18:34:41 +01:00
69fe1d6074 Implement iso_tree_add_new_file() to add new files from scratch. 2008-03-08 17:28:40 +01:00
0c69463c5a Add support for adding a node with a given name. 2008-03-08 01:06:46 +01:00
ae43626f0b Definitelly fix ticket #127. Iterators now support asynchronous remove. 2008-03-08 00:45:19 +01:00
620c7a08e1 Add an Unit test to asyncronous removing of children during iteration. 2008-03-07 00:21:18 +01:00
edc5ccf90a Added iterator global registry. 2008-03-06 23:59:32 +01:00
d534a96c83 Apply patch by "eostapets" fixing a linking bug. 2008-03-06 16:13:15 +01:00
085f6b64a3 Add find condition to logically combine two find conditions. 2008-03-04 01:10:56 +01:00
d2a92bd0f6 Add find contitions to check for timestamps. 2008-03-04 00:53:25 +01:00
6b583aa31f Add find conditions to check for mode, gid and uid attributes. 2008-03-04 00:34:17 +01:00
cb47296913 Preliminary support for find nodes. 2008-03-03 22:02:10 +01:00
dd02d1d976 Convert IsoDirIter in an interface. 2008-03-03 21:18:54 +01:00
c75f1a430e Added function to get the lba of an old image file. 2008-03-03 20:42:06 +01:00
d894d3719b Some little unit test assert. 2008-03-02 18:21:58 +01:00
6d633caadb Improved DirIter implementation. 2008-03-02 18:20:19 +01:00
955f2f9c24 Added a test case that shows 2nd bug found by Thomas in ticket #126. 2008-03-02 17:08:59 +01:00
061dce1ec2 s/openned/opened. Deprecate incorrectly spelled errors. 2008-03-01 17:12:44 +01:00
31a92bd8bd Ensure filters are only applied to repeatable Streams. 2008-03-01 17:12:27 +01:00
b3ef67feb6 Test case for iso_dir_iter_take(). 2008-03-01 16:27:54 +01:00
241a7295ba Ticket #127 also affects iso_dir_iter_take(). Fixed. 2008-03-01 16:16:12 +01:00
b9331ba5c1 Fix bug in iso_dir_iter_remove(), ticket #127. 2008-03-01 15:57:12 +01:00
0dad87f035 Filters definition. Example XOR_encrypt filter. 2008-02-24 18:20:23 +01:00
37f69d5360 Remove IsoStream->get_name(), add version and type fields instead. 2008-02-24 16:58:07 +01:00
811743a147 Expose IsoStream and getter for IsoFile. API still not stable. 2008-02-23 18:03:12 +01:00
3c97b494b6 Merge Mario mainline changes. 2008-02-23 01:39:09 +01:00
7b7fc4ddc1 Created empty news stub for v0.6.4 2008-02-23 01:19:16 +01:00
d835235a93 Updated NEWS file for bugfix release 2008-02-23 01:17:19 +01:00
e5f1cfca40 Merge more Thomas contributions related to ticket #125. 2008-02-23 01:07:30 +01:00
353ed64d77 bundle_A80222_3 2008-02-22 22:43:30 +01:00
e80ae930ea Merge changes from Thomas (ticket #125). Minor changes on merge. 2008-02-22 21:42:17 +01:00
5a2ab22b81 Change version number to 0.6.3. 2008-02-22 21:24:20 +01:00
25ab8631e4 bundle_A80222_2 2008-02-22 19:43:09 +01:00
3fa3292564 message enhancements 2nd edition 2008-02-22 19:39:09 +01:00
9c73b108f7 Fix bug to include buffer-h in dist tarball. 2008-02-22 15:57:57 +01:00
a98b4eda40 ticket 125 2008-02-22 15:39:35 +01:00
71 changed files with 19639 additions and 2401 deletions

View File

@ -38,3 +38,4 @@ demo/isogrow
doc/html
doc/doxygen.conf
libisofs-1.pc
demo/find

View File

@ -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

View File

@ -5,9 +5,8 @@ Copyright (C) 2007-2008 Vreixo Formoso, Mario Danic, Thomas Schmitt
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of

View File

@ -1,4 +1,8 @@
pkgconfigdir=$(libdir)/pkgconfig
# ts A90315 : LIBBURNIA_PKGCONFDIR is defined OS specific in acinclude.m4
# was: pkgconfigdir=$(libdir)/pkgconfig
pkgconfigdir=$(LIBBURNIA_PKGCONFDIR)
libincludedir=$(includedir)/libisofs
lib_LTLIBRARIES = libisofs/libisofs.la
@ -9,6 +13,13 @@ lib_LTLIBRARIES = libisofs/libisofs.la
libisofs_libisofs_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
# Eventually enabling system adapters for ACL and EA.
# ts A90409: Eventually enabling use of zlib.
libisofs_libisofs_la_CFLAGS = $(LIBACL_DEF) $(XATTR_DEF) $(ZLIB_DEF)
# ts A90114 : added aaip_0_2.*
libisofs_libisofs_la_SOURCES = \
libisofs/builder.h \
libisofs/builder.c \
@ -16,6 +27,7 @@ libisofs_libisofs_la_SOURCES = \
libisofs/node.c \
libisofs/tree.h \
libisofs/tree.c \
libisofs/find.c \
libisofs/image.h \
libisofs/image.c \
libisofs/fsource.h \
@ -28,6 +40,12 @@ libisofs_libisofs_la_SOURCES = \
libisofs/libiso_msgs.c \
libisofs/stream.h \
libisofs/stream.c \
libisofs/filter.h \
libisofs/filter.c \
libisofs/filters/xor_encrypt.c \
libisofs/filters/external.c \
libisofs/filters/zisofs.c \
libisofs/filters/gzip.c \
libisofs/util.h \
libisofs/util.c \
libisofs/util_rbtree.c \
@ -39,6 +57,7 @@ libisofs_libisofs_la_SOURCES = \
libisofs/ecma119_tree.h \
libisofs/ecma119_tree.c \
libisofs/writer.h \
libisofs/buffer.h \
libisofs/buffer.c \
libisofs/rockridge.h \
libisofs/rockridge.c \
@ -47,9 +66,16 @@ libisofs_libisofs_la_SOURCES = \
libisofs/joliet.c \
libisofs/eltorito.h \
libisofs/eltorito.c \
libisofs/system_area.h \
libisofs/system_area.c \
libisofs/make_isohybrid_mbr.c \
libisofs/iso1999.h \
libisofs/iso1999.c \
libisofs/data_source.c
libisofs/data_source.c \
libisofs/aaip_0_2.h \
libisofs/aaip_0_2.c
libisofs_libisofs_la_LIBADD= \
$(THREAD_LIBS)
libinclude_HEADERS = \
libisofs/libisofs.h
@ -61,79 +87,100 @@ noinst_PROGRAMS = \
demo/cat \
demo/catbuffer \
demo/tree \
demo/find \
demo/ecma119tree \
demo/iso \
demo/isoread \
demo/isocat \
demo/isomodify \
demo/isoms \
demo/isogrow
demo/isoms
# demo/isogrow
demo_lsl_CPPFLAGS = -Ilibisofs
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
demo_lsl_SOURCES = demo/lsl.c
demo_cat_CPPFLAGS = -Ilibisofs
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
demo_cat_SOURCES = demo/cat.c
demo_catbuffer_CPPFLAGS = -Ilibisofs
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_catbuffer_SOURCES = demo/cat_buffer.c
demo_tree_CPPFLAGS = -Ilibisofs
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_tree_SOURCES = demo/tree.c
demo_find_CPPFLAGS = -Ilibisofs
demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_find_SOURCES = demo/find.c
demo_ecma119tree_CPPFLAGS = -Ilibisofs
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_ecma119tree_SOURCES = demo/ecma119_tree.c
demo_iso_CPPFLAGS = -Ilibisofs
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(libisofs_libisofs_la_LIBADD)
demo_iso_SOURCES = demo/iso.c
demo_isoread_CPPFLAGS = -Ilibisofs
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isoread_SOURCES = demo/iso_read.c
demo_isocat_CPPFLAGS = -Ilibisofs
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isocat_SOURCES = demo/iso_cat.c
demo_isomodify_CPPFLAGS = -Ilibisofs
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isomodify_SOURCES = demo/iso_modify.c
demo_isoms_CPPFLAGS = -Ilibisofs
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) \
$(libisofs_libisofs_la_LIBADD)
demo_isoms_SOURCES = demo/iso_ms.c
demo_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn
demo_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lburn
demo_isogrow_SOURCES = demo/iso_grow.c
# demo_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn
# demo_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) \
# $(libisofs_libisofs_la_LIBADD) \
# -lburn
# demo_isogrow_SOURCES = demo/iso_grow.c
## Build unit test
## ts A90428 , ticket 147, The test code does not use the API and is totally
## outdated in its creation of mocked objects.
## A volunteer is needed to rewrite it using the API.
# ## Build unit test
check_PROGRAMS = \
test/test
test_test_CPPFLAGS = -Ilibisofs
test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lcunit
test_test_LDFLAGS = -L.. -lm
test_test_SOURCES = \
test/test.h \
test/test.c \
test/test_node.c \
test/test_image.c \
test/test_tree.c \
test/test_util.c \
test/test_rockridge.c \
test/test_stream.c \
test/mocked_fsrc.h \
test/mocked_fsrc.c
# check_PROGRAMS = \
# test/test
#
# test_test_CPPFLAGS = -Ilibisofs
# test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) \
# $(libisofs_libisofs_la_LIBADD) -lcunit
# test_test_LDFLAGS = -L.. -lm
#
# test_test_SOURCES = \
# test/test.h \
# test/test.c \
# test/test_node.c \
# test/test_image.c \
# test/test_tree.c \
# test/test_util.c \
# test/test_rockridge.c \
# test/test_stream.c \
# test/mocked_fsrc.h \
# test/mocked_fsrc.c
## ========================================================================= ##
@ -162,6 +209,8 @@ uninstall-local:
nodist_pkgconfig_DATA = \
libisofs-1.pc
# ts A80114 : added aaip-os*
EXTRA_DIST = \
libisofs-1.pc.in \
version.h.in \
@ -171,9 +220,15 @@ EXTRA_DIST = \
AUTHORS \
COPYRIGHT \
COPYING \
NEWS \
INSTALL \
TODO \
ChangeLog \
Roadmap
NEWS \
INSTALL \
TODO \
ChangeLog \
Roadmap \
doc/susp_aaip_2_0.txt \
doc/susp_aaip_isofs_names.txt \
doc/zisofs_format.txt \
libisofs/aaip-os-dummy.c \
libisofs/aaip-os-linux.c \
libisofs/aaip-os-freebsd.c

20
NEWS
View File

@ -1,3 +1,23 @@
== Sun Apr 27 2008 ==
Libisofs v0.6.4
===============
- Extended information: iso_node_add_xinfo()
- New node iteration: iso_dir_find_children()
- Custom image file content via iso_tree_add_new_file()
- Missing feature added to map a disk file to an
arbitrary image file path via iso_tree_add_new_node()
- Obtain image path of a node object via iso_tree_get_node_path()
- Various bugfixes
== Fri Feb 22 2008 ==
Libisofs v0.6.2.1
=================
- FIX: missing buffer.h in tarball
== Thu Feb 14 2008 ==
Libisofs v0.6.2

1
TODO
View File

@ -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

View File

@ -1,6 +1,7 @@
AC_DEFUN([TARGET_SHIZZLE],
[
ARCH=""
LIBBURNIA_PKGCONFDIR="$libdir"/pkgconfig
AC_MSG_CHECKING([target operating system])
@ -12,9 +13,12 @@ AC_DEFUN([TARGET_SHIZZLE],
*-*-freebsd*)
ARCH=freebsd
LIBBURN_ARCH_LIBS=-lcam
LIBBURNIA_PKGCONFDIR=$(echo "$libdir" | sed 's/\/lib$/\/libdata/')/pkgconfig
;;
*)
AC_ERROR([You are attempting to compile for an unsupported platform])
ARCH=
LIBBURN_ARCH_LIBS=
# AC_ERROR([You are attempting to compile for an unsupported platform])
;;
esac

View File

@ -1,4 +1,4 @@
AC_INIT([libisofs], [0.6.2], [http://libburnia-project.org])
AC_INIT([libisofs], [0.6.20], [http://libburnia-project.org])
AC_PREREQ([2.50])
dnl AC_CONFIG_HEADER([config.h])
@ -44,7 +44,7 @@ dnl If LIBISOFS_*_VERSION changes, be sure to change AC_INIT above to match.
dnl
LIBISOFS_MAJOR_VERSION=0
LIBISOFS_MINOR_VERSION=6
LIBISOFS_MICRO_VERSION=2
LIBISOFS_MICRO_VERSION=20
LIBISOFS_VERSION=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION.$LIBISOFS_MICRO_VERSION
AC_SUBST(LIBISOFS_MAJOR_VERSION)
@ -54,10 +54,11 @@ AC_SUBST(LIBISOFS_VERSION)
dnl Libtool versioning
LT_RELEASE=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION
# SONAME = 6 - 0 = 6 . Library name = libisofs.6.0.0
LT_CURRENT=6
# 2009.05.30 development jump has not yet happened
# SONAME = 22 - 16 = 6 . Library name = libisofs.6.16.0
LT_CURRENT=22
LT_REVISION=0
LT_AGE=0
LT_AGE=16
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
AC_SUBST(LT_RELEASE)
@ -84,6 +85,10 @@ if test ! $ac_cv_func_fseeko; then
AC_MSG_ERROR([Libisofs requires largefile support.])
fi
dnl If iconv(3) is in an extra lib, then it gets added to variable LIBS.
dnl If not, then no -liconv will be added.
AC_CHECK_LIB(iconv, iconv, , )
AC_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)
LIBTOOL="$LIBTOOL --silent"
@ -119,6 +124,7 @@ AC_SUBST(THREAD_LIBS)
TARGET_SHIZZLE
AC_SUBST(ARCH)
AC_SUBST(LIBBURNIA_PKGCONFDIR)
AC_SUBST(LIBBURN_ARCH_LIBS)
dnl Add compiler-specific flags
@ -146,6 +152,53 @@ AC_ARG_ENABLE(verbose-debug,
AC_DEFINE(LIBISOFS_VERBOSE_DEBUG, 1))
dnl ts A90123
AC_ARG_ENABLE(libacl,
[ --enable-libacl Enable use of libacl by libisofs, default=yes],
, enable_libacl=yes)
if test x$enable_libacl = xyes; then
dnl Check whether there is libacl-devel and libacl-runtime.
dnl If not, erase this macro which would enable use of acl_to_text and others
LIBACL_DEF="-DLibisofs_with_aaip_acL"
dnl The empty yes case obviously causes -lacl to be linked
AC_CHECK_HEADER(sys/acl.h, AC_CHECK_LIB(acl, acl_to_text, , LIBACL_DEF= ), LIBACL_DEF= )
else
LIBACL_DEF=
fi
AC_SUBST(LIBACL_DEF)
dnl ts A90123
AC_ARG_ENABLE(xattr,
[ --enable-xattr Enable use of xattr by libisofs, default=yes],
, enable_xattr=yes)
if test x$enable_xattr = xyes; then
dnl Check whether there is the header for Linux xattr.
dnl If not, erase this macro which would enable use of listxattr and others
XATTR_DEF="-DLibisofs_with_aaip_xattR"
AC_CHECK_HEADER(attr/xattr.h, AC_CHECK_LIB(c, listxattr, X= , XATTR_DEF= ), XATTR_DEF= )
else
XATTR_DEF=
fi
AC_SUBST(XATTR_DEF)
dnl ts A90409
AC_ARG_ENABLE(zlib,
[ --enable-zlib Enable use of zlib by libisofs, default=yes],
, enable_zlib=yes)
if test x$enable_zlib = xyes; then
dnl Check whether there is the header for zlib.
dnl If not, erase this macro which would enable use of compress2() and others.
dnl The empty parameter after "compress2" causes -lz.
ZLIB_DEF="-DLibisofs_with_zliB"
AC_CHECK_HEADER(zlib.h, AC_CHECK_LIB(z, compress2, , ZLIB_DEF= ), ZLIB_DEF= )
else
ZLIB_DEF=
fi
AC_SUBST(ZLIB_DEF)
AC_CONFIG_FILES([
Makefile
doc/doxygen.conf

63
demo/find.c Normal file
View 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;
}

View File

@ -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;

View File

@ -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>

View File

@ -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>

View File

@ -39,7 +39,7 @@ print_type(mode_t mode)
case S_IFREG: printf("[R] "); break;
case S_IFBLK: printf("[B] "); break;
case S_IFDIR: printf("[D] "); break;
case S_IFIFO: printf("[F] "); break;
case S_IFIFO: printf("[F] "); break;
}
}
@ -51,6 +51,7 @@ print_file_src(IsoFileSource *file)
iso_file_source_lstat(file, &info);
print_type(info.st_mode);
print_permissions(info.st_mode);
printf(" %10llu ", info.st_size);
//printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
name = iso_file_source_get_name(file);
printf(" %s", name);
@ -116,7 +117,7 @@ int main(int argc, char **argv)
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
result = iso_data_source_new_from_file(argv[1], &src);
if (result < 0) {
printf ("Error creating data source\n");
@ -134,10 +135,10 @@ int main(int argc, char **argv)
printf ("Error creating filesystem\n");
return 1;
}
printf("\nVOLUME INFORMATION\n");
printf("==================\n\n");
printf("Vol. id: %s\n", iso_image_fs_get_volume_id(fs));
printf("Publisher: %s\n", iso_image_fs_get_publisher_id(fs));
printf("Data preparer: %s\n", iso_image_fs_get_data_preparer_id(fs));
@ -149,7 +150,7 @@ int main(int argc, char **argv)
printf("\nDIRECTORY TREE\n");
printf("==============\n");
result = fs->get_root(fs, &root);
if (result < 0) {
printf ("Can't get root %d\n", result);
@ -158,7 +159,7 @@ int main(int argc, char **argv)
//print_file_src(root);
print_dir(root, 0);
iso_file_source_unref(root);
fs->close(fs);
iso_filesystem_unref((IsoFilesystem*)fs);
iso_data_source_unref(src);

View File

@ -0,0 +1,58 @@
===============================================================================
ISO-9660 Level 3 Cookbook
===============================================================================
Creation date: 2008-Aug-17
Author: Vreixo Formoso
_______________________________________________________________________________
Contents:
---------
1. References
2. General
3. OS Support
4. Implementation
-------------------------------------------------------------------------------
1. References:
ECMA-119 "Volume and File Structure of CDROM for Information Interchange"
-------------------------------------------------------------------------------
2. General
In ECMA-119 standard, the size of a file section cannot be bigger than 4GB - 1,
because the Data Length field of the Directory Record is just 32 bits (9.1.4).
However, "each file shall consist of one or more File Sections" (6.5.1), and
that way we can store files greater than 4GB in a ECMA-119 image. Such image,
with multiple File Sections, is only supported at Level 3 (10.3), as Level 2
(10.2) states that "each file shall consist of only one File Section".
On disc, each file section is stored in a Extent (6.4.2), i.e. a set of
contiguous Logical Blocks.
-------------------------------------------------------------------------------
3. OS Support
Wikipedia states that "Microsoft Windows XP supports this, while Mac OS X
(as of 10.4.8) does not handle this case properly. In the case of Mac OS X,
the driver appears not to support file fragmentation at all (i.e. it only
supports ISO 9660 Level 2 but not Level 3). Linux supports multiple extents.
FreeBSD only shows and reads the last extent of a multi-extent file."
-------------------------------------------------------------------------------
4. Implementation
Each File Section will have its own Directory Record (6.5.1). So, for files
greater than 4 GB, we need to store several directory records, that will have
the same File Identifier, and stored in the order of the File Sections they
refer (9.3).
All but the last Directory Record must have the Multi-Extent flag set (9.1.6)

445
doc/susp_aaip_2_0.txt Normal file
View File

@ -0,0 +1,445 @@
Arbitrary Attribute Interchange Protocol
Version 2.0
Mar 18 2009
Interchange of Persistent File Attributes
by Thomas Schmitt - mailto:scdbackup@gmx.net
Libburnia project - mailto:libburn-hackers@pykix.org
AAIP is intended as companion of the Rock Ridge Interchange Protocol RRIP
which under the general design of System Use Sharing Protocol SUSP extends
ISO 9660 aka ECMA-119 filesystem semantics to match POSIX needs.
Goal is to have for each file an arbitrary number of attributes which consist
of two components (Name and Value) of arbitrary length and to have a compact
representation of ACLs.
This document describes a SUSP entry with Signature Word "AL" which collides
neither with SUSP 1.12 nor with RRIP 1.12. The AL entry has been designed
to be as similar to the RRIP entry SL as possible.
The presence of AAIP shall be announced by a particular ER entry.
Since the size of a SUSP entry is limited to 255, multiple entries may be
needed to describe one component. The CE mechanism of SUSP shall be used to
address enough storage if needed.
AL entries and the ER entry of AAIP shall only be present if the ER entry
of RRIP is present.
-------------------------------------------------------------------------------
System Entries Provided by this Specification
* AL
Description of the "AL" System Use Entry
The entry has exactly the same layout as RRIP entry SL. One has to expect
more data bytes than with SL, though, and any of the 256 possible byte values.
The reader shall be prepared to detect and handle oversized data.
One or more AL entries form the Attribute List of a file object with
an even number of components. Each two consequtive components form a pair of
Name and Value.
The empty name indicates that the value is a compact representation of ACLs.
Names must not contain byte value 0x00. Names which begin by bytes 0x01 to 0x1f
represent names in particular namespaces. See below: Namespaces.
The meaning of any other names or name parts is not specified by this document.
All AL entries except the last one shall have the CONTINUE flag set. An AL
entry with CONTINUE set to 0 indicates the end of the Attribute List.
The format of the AL System Use Field is as follows:
[1] "BP 1 to BP 2 - Signature Word" shall be (41)(4C) ("AL").
[2] "BP 3 - Length" shall specify as an 8-bit number the length in bytes of
the AL entry recorded according to ISO 9660:7.1.1.
[3] "BP 4 - System Use Entry Version" shall be 1 as in ISO 9660:7.1.1.
[4] "BP 5 - Flags" shall contain bit field flags numbered 0 to 7 starting
with the least significant bit as follows:
0 CONTINUE This AL entry continues in the next AL entry.
All other bits shall be set to 0.
[5] "BP 6 to Length - Component Area" shall contain Component Records
as described below.
| 'A' | 'L' | LENGTH | 1 | FLAGS | COMPONENT AREA |
Within AL entries each component (Name or Value) shall be recorded as one
or more component records. If a component does not fit into the remaining
space of an AL entry then it shall be continued in following AL entries.
All Component Records of a component except the last one shall have the
CONTINUE flag set. A Component Record with CONTINUE set to 0 indicates the end
of the component. An eventually following Component Record starts the next
component.
-------------------------------------------------------------------------------
The Component Record format is identical to the one of the SL entry.
The complete form of the following summary can be found in RRIP 1.12 "4.1.3.1".
In case of discrepancies, RRIP 1.12 is the decisive specification. Please
inform the author of this document if you find such a discrepancy.
Component Records shall be recorded contiguously within each Component Area,
starting in the first byte of the Component Area. The last Component Record
in the Component Area of an AL System Use Entry may be continued in the
Component Area of the next recorded AL System Use Entry in the same
System Use Area.
Each Component Record shall have the following format:
[A] "BP 1 - Component Flags" shall contain bit field flags numbered 0 to 7,
starting with the least significant bit, as follows:
0 CONTINUE This Component Record continues in the next
AL Component Record.
all others are RESERVED and shall be 0.
[B] "BP 2 - Component Length (LEN_CP)" shall specify as an 8-bit number the
number of component bytes in the Component Record. This length shall not
include the first two bytes of the Component Record.
If any of the bit positions 1-3 is set, the value of this field shall be
set to ZERO and no Component Content shall be recorded.
This field shall be recorded according to ISO 9660 Format section 7.1.1.
[C] "BP 3 to 2 + LEN_CP - Component Content" shall contain the component
bytes in the Component Record.
| COMPONENT FLAGS | LEN_CP | COMPONENT BYTES |
Example: Two pairs of "name"="long...content" and "one"="more" encoded as
two AL entries
Field 1 contains the Component Record of Name and one Component Record of
Value :
{ 'A', 'L', 255, 1, 1,
0, 4, 'n', 'a', 'm', 'e',
1, 255, 'l', 'o', 'n', 'g', ... 238 more bytes, 13 go to next AL ... }
Field 2 contains the rest of "long...content" and the complete second pair.
It marks the end of the Attribute List :
{ 'A', 'L', 38, 1, 0,
... 13 remaining bytes of the Component Record in first entry ...
0, 7, 'c', 'o', 'n', 't', 'e', 'n', 't',
0, 3, 'o', 'n', 'e',
0, 4, 'm', 'o', 'r', 'e' }
-------------------------------------------------------------------------------
Namespaces
AAIP provides a short notation for namespaces which uses a single non-printable
byte at the start of the name.
Reserved start bytes of names are
0x01 to 0x1F
The names of extended file attributes are traditionally organized in
namespaces, which get expressed as first part of an attribute name up to a
period "." character. It is also tradition that names are printable text,
single words and especially contain no 0-bytes.
AAIP does not enforce the use of any namespace but it urges that names in the
following registered namespaces are used according to traditions.
The namespaces "system." and "user." are available with many file system
types. "system." is file system dependent and often restricted in the
choice of names. "user." is portable and allows to choose about any name.
Namespace "isofs." is defined for internal use of AAIP enhanced ISO 9660
file systems. Names in this namespace should be registered at libburnia.org.
Further namespaces may be registered at libburnia.org.
The reserved start bytes of names have the following meaning
0x01 escape reserved character at start of name
0x02 namespace "system."
0x03 namespace "user."
0x04 namespace "isofs."
0x05 namespace "trusted."
0x06 namespace "security."
0x07 to 0x1F shall not be used yet.
Examples:
Name "user.abc" with and without short notation. Both is allowed.
0, 4, 0x03, 'a', 'b', 'c'
0 8, 'u', 's', 'e', 'r', '.', 'a', 'b', 'c'
Name "\003abc" (if really desired)
0, 5, 0x01, 0x03, 'a', 'b', 'c'
-------------------------------------------------------------------------------
Specification of binary ACL representation as special Arbitrary Attribute
The Name component of a binary ACL shall be of length 0.
The Value shall be an arbitrary number of ACL Entries:
[a] "BP 1 - Entry Flags" shall contain bit field flags numbered 0 to 7,
starting with the least significant bit, as follows:
0 EXEC indicates that this entry grants execute permission
1 WRITE write permission
2 READ read permission
3 QUALIFIER indicates that one or more Qualifier Records follow
4 - 7 TYPE
shall contain the tag type of the ACL entry as four bit code:
0 TRANSLATE Entry for a global map of name to numeric id
Qualifier is a record of number and text
1 ACL_USER_OBJ Permissions of owning user (as of PX entry)
3 ACL_GROUP_OBJ Permissions of owning group (as of PX entry)
5 ACL_MASK Restricts 10, 3, and 12 via logical AND
6 ACL_OTHER Permissions of non-listed, non-owning users
8 SWITCH_MARK Switch from "access" ACL to "default" ACL
10 ACL_USER_N Permissions of arbitrary user. Qualifier is
the numeric user id (max. 4 bytes).
12 ACL_GROUP_N Permissions of arbitrary group. Qualifier is
the numeric group id (max. 4 bytes).
15 FUTURE_VERSION Will indicate that this document
does not apply to the entry.
The other values are reserved. Readers shall ignore them if
they are not aware of updates of this document which would
assign a meaning to them.
The entries must match the permission bits of the PX entry. This shall obey the
rule that ACL_USER_OBJ must match S_IRWXU, ACL_OTHER must match S_IRWXO,
ACL_MASK - if present - must match S_IRWXG, else ACL_GROUP_OBJ must match
S_IRWXG. If there is ACL_USER_N or ACL_GROUP_N there must also be ACL_MASK.
A numeric qualifier is a binary number of variable length up to 4 bytes. The
Most Significant Byte comes first. The number shall be the "POSIX File User ID"
resp. "POSIX File Group ID" as also used in RRIP PX entries. The ids of owning
user and owning group shall be taken from the PX entry of the file object.
Optional TRANSLATE entries may associate user or group names with numeric
ids to allow the reading system to remap the numeric ids. See below.
The writer is not obliged to write them and the reader is not obliged to
interpret them.
The ACL entries belong to the "access" ACL of a file object. An optional
SWITCH_MARK entry may direct further entries to the "default" ACL which
is defined for directory objects. The EXEC bit of SWITCH_MARK shall be 1.
The bits for WRITE, READ, QUALIFIER shall be 0.
An eventually needed qualifier is stored in one or more Qualifier Records.
[b] "BP 2 - Qualifier Record Head" shall be present only if QUALIFIER is set
to 1. It shall give the number of Qualifier Bytes and eventually
indicate that the qualifier continues in a Qualifier Record which comes
imediately after this record.
0 to 127 Q_LENGTH, the qualifier is complete by this record
128 to 255 Q_LENGTH+128, the qualifier is continued by next record
So a Qualifier Record can contain at most 127 Qualifier Bytes.
This field shall be recorded according to ISO 9660 Format section 7.1.1.
[c] "BP 3 to BP 2 + Q_LENGTH - Qualifier Bytes" shall be present only if
QUALIFIER is set to 1 and hold the announced number of bytes of the
user or group name.
| ENTRY FLAGS [ | QUALIFIER HEAD | QUALIFIER BYTES | ]
Example: From man 5 acl: u::rw-,u:lisa:rw-,g::r--,g:toolies:rw-,m::r--,o::r--
"lisa" has user number 123, "toolies" has group number 65534
{ 'A', 'L', 20, 1, 0,
0, 0,
0, 11, 0x16,
0xAE, 1, 123,
0x34,
0xCE, 2, 255, 254,
0x54,
0x64 }
Example: "Access" ACL and "default" ACL (0x81 is the switch mark)
u::rwx,g::r-x,o::r-x, du::rwx,dg::r-x,dm::rwx,do::r-x,du:lisa:rwx
{ 'A', 'L', 20, 1, 0,
0, 0,
0, 11, 0x17, 0x35, 0x65,
0x81,
0x17, 0x35, 0x57, 0x65,
0xA7, 1, 123 }
-------------------------------------------------------------------------------
Association of Names and Numeric Identifiers
The entry flag value 0x08 TRANSLATE is not a ACL entry of the hosting object
but rather a global hint about the relation of roles, names and numeric ids.
If it is recorded at all, then it shall be recorded with the first Directory
Entry of the volume's root directory. According to the description of SUSP
entry ER, this has to be "dot" or (00). Other than with ER, a TRANSLATE entry
may not appear in the root of directory sub trees.
An interested reader shall examine the Arbitrary Attributes of this Directory
Entry in order to collect a translation table.
The advised translation is: PX or AL Id number -> name -> local id number.
The Qualifier Bytes of a TRANSLATE entry shall have the following format:
[i] "BP 0 - Role" shall tell whether it is about a user name (role 0) or
a group name (role 1). Other values are not allowed.
[ii] "BP 1 to BP 8 - Numeric Id" shall hold the 32 bit POSIX Id number of the
entry. This field shall be recorded according to ISO 9660:7.3.3.
[iii] "BP 9 to End Of Qualifier - Name" shall hold the name bytes of this
entry.
| ROLE | NUMERIC ID | NAME |
Example: User id number 123 gets associated with user name "lisa"
0x08, 13, 0, 123,0,0,0, 0,0,0,123, 'l', 'i', 's', 'a',
Example: A very long qualifier naming "His_Excellency_..._the_Boss" as user #1.
This needs two qualifier records.
0x08, 255, 0, 1,0,0,0, 0,0,0,1,
'H', 'i', 's', '_', 'E', 'x', 'c', 'e', 'l', 'e',
... 108 more bytes ...
8, 't', 'h', 'e', '_', 'B', 'o', 's', 's',
-------------------------------------------------------------------------------
Specification of the ER System Use Entry Values for AAIP:
This ER system entry shall only be present if the ER entry of RRIP is present.
To be compliant with SUSP-1.12, this ER entry must be present if AL entries
are present, and ES entries have to mark RRIP and AAIP entries.
If for some reason compliance with SUSP-1.10 is intended, then this ER entry
and the ES entries must not be present, although SUSP-1.10 would allow ER.
(See below: Compatibility considerations.)
The Extension Version number for this version of AAIP shall be 1.
The Extension Identifier field shall be "AAIP_0200" with Identifier Length 9.
The mandatory content form of the Extension Descriptor is
"AL PROVIDES VIA AAIP 2.0 SUPPORT FOR ARBITRARY FILE ATTRIBUTES IN ISO 9660 IMAGES"
The Description Length is 81.
The recommended content of the Extension Source is
"PLEASE CONTACT THE LIBBURNIA PROJECT VIA LIBBURNIA-PROJECT.ORG".
The corresponding Source Length is 62.
-------------------------------------------------------------------------------
Compatibility Considerations
This extension is supposed not to disturb any reader system which complies
to SUSP-1.10:
"6.2 Requirements for a Receiving System
[...]
Any System Use Field which the receiving system does not recognize
is to be ignored and skipped."
SUSP-1.12 extends this prescription by:
"Any System Use Entry, with the exception of the set of System Use Entries
defined in this document, following an "ES" System Use Entry that indicates
an extension specification which the receiving system does not recognize
shall be ignored and skipped."
According to SUSP-1.12 the ER entry is mandatory for a conformant extension.
It also prescribes that in the case that ER entries of RRIP and AAIP are
present, then ES entries shall be used to separate RRIP entries from AAIP
entries.
SUSP-1.12 frowns on extensions which are not announced by ER. Nevertheless
is does not totally outrule them.
SUSP-1.10 does not specify ES entries at all and allows to have extension
entries without announcing them by an ER entry. So if a second ER entry is
not bearable, then the SUSP-1.10 downgrade of AAIP allows to omit the
AAIP ER and the ES entries. But if there is the AAIP ER then there must be ES
at the appropriate places. Else the format would explicitely violate SUSP-1.12.
-------------------------------------------------------------------------------
Model Relations:
Attribute List ------------- [1:0..1] ------------- ACL
[1:0..n] [1:0..n]
Arbitrary Attribute ( [1:0..1] ACL ) Entry
[1:2..2n] [1:0..1]
Component ( [1..m:1..n] AL Field ) Qualifier
[1:1..n] << one of >>
Component Record / \
[1..m:1..n] Translation Entry , Numeric Id
AL Field | |
[1:1..n] [1:1]
\ /
Qualifier Record
-------------------------------------------------------------------------------
Revoked drafts:
The following outdated versions may be interpreted at read time but they
shall not be written any more.
AAIP-1.0
Previous versions up to AAIP 1.0 used field signature "AA" rather than "AL".
This nearly collides with "Apple ISO 9660 Extensions". The Apple "AA" field of
version 1 has a length of 7, whereas the shortest first AAIP field "AA" had
length 9.
Beginning with AAIP 2.0, the field name has been changed to "AL".
If a reader interprets old AAIP "AA" fields, then it must take precautions to
distinguish them from Apple "AA" fields. But it is well compliant with AAIP 2.0
to just ignore any kind of "AA" fields.
AAIP 1.0 had ER signature "AAIP_0100".
AAIP-0.2
AAIP 0.2 with ER signature "AAIP_0002" allowed to announce and use a different
signature than "AA". This was revoked because ES entries serve the purpose
to distinguish AAIP entries from eventual "AA" entries of any other extension.
Regrettably no reader (kernel) was found which neatly interprets ES. Many do
not even recognize the RRIP-1.12 ER signatures "IEEE_P1282", "IEEE_1282".
AAIP 0.2 defined two ACL types which did not make it into AAIP 1.0
2 ACL_USER of arbitrary user, with name as qualifier
4 ACL_GROUP of arbitrary group, with name as qualifier
Their job was transferred to ACL_USER_N and ACL_GROUP_N which have numeric
qualifiers.
AAIP-0.0
There was a draft AAIP 0.0 with ER signature "AAIP_2008A". It did not resemble
the existing entry SL and was never implemented.
-------------------------------------------------------------------------------
References:
ECMA-119 aka ISO 9660
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
SUSP 1.12 (entries CE , PD , SP , ST , ER , ES)
ftp://ftp.ymi.com/pub/rockridge/susp112.ps
RRIP 1.12 (entries PX , PN , SL , NM , CL , PL , RE , TF , SF , obsolete: RR)
ftp://ftp.ymi.com/pub/rockridge/rrip112.ps
Apple ISO 9660 Extensions (entries AA and BA)
http://developer.apple.com/technotes/fl/fl_36.html
Amiga AS entry
http://www.estamos.de/makecd/Rock_Ridge_Amiga_Specific
zisofs entry ZF (prepared by zisofs-tools, written by mkisofs)
http://freshmeat.net/projects/zisofs-tools/
Program mkisofs emits entry XA
ftp://ftp.berlios.de/pub/cdrecord/alpha
-------------------------------------------------------------------------------

View File

@ -0,0 +1,85 @@
Arbitrary Attribute Interchange Protocol
Interchange of Persistent File Attributes
Directory of Namespace "isofs."
by Thomas Schmitt - mailto:scdbackup@gmx.net
Libburnia project - mailto:libburn-hackers@pykix.org
The following names are defined for AAIP namespace "isofs." as mentioned in
specification of AAIP :
-------------------------------------------------------------------------------
Name:
isofs.di
Purpose:
Records .st_dev and .st_ino of struct stat of the file source in the
local filesystem. See man 2 stat.
Format of Value:
DEV_LEN | DEV_BYTES | INO_LEN | INO_BYTES
The _LEN fields comply to ISO 9660 Format section 7.1.1.
The byte strings begin with the most significant byte.
Example:
Device number 2001, inode number 176343
{ 2, 7, 209,
3, 2, 176, 215 }
Registered:
17 Feb 2009 by Thomas Schmitt for xorriso.
-------------------------------------------------------------------------------
Name:
isofs.cs
Purpose:
Records the name of the character set that was used as output character
set when writing the RRIP name tree of the ISO 9660 image. It shall be
suitable as parameter for function iconv_open(3).
This attribute shall eventually be attached to the root directory entry
and be global for the whole image.
Format of Value:
Shall hold the character set name without terminating 0-byte.
Example:
{ 'I', 'S', 'O', '-', '8', '8', '5', '9' , '-', '1' }
Registered:
18 Mar 2009 by Thomas Schmitt for libisofs.
-------------------------------------------------------------------------------
Name:
isofs.st
Purpose:
Records a time point at least 1 second before any nodes were added to a
freshly loaded or created ISO image. Nodes in the image which have
younger timestamps are suspect to have changed their content during
image production and might bear inconsistent content.
The RRIP timestamps have a blind second during which a change after
node registration would not be recognizable for incremental backups
which are based in "isofs.di" rather than on content comparison.
This attribute shall eventually be attached to the root directory entry
and be global for the whole image.
Format of Value:
Shall hold UTC seconds since 1970 as decimal number string without
terminating 0-byte.
Example:
{ '1', '2', '3', '8', '7', '4', '2', '2', '9', '6' }
Registered:
03 Apr 2009 by Thomas Schmitt for xorriso.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------

143
doc/zisofs_format.txt Normal file
View File

@ -0,0 +1,143 @@
Description of the zisofs Format
as of zisofs-tools-1.0.8 by H. Peter Anvin
and cdrtools-2.01.01a39 by Joerg Schilling
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
- distribute freely , please report any errors or ambiguities -
Apr 11 2009
The zisofs format was invented by H. Peter Anvin. It compresses data file
content, marks it by a header and provides a pointer array for coarse random
access. Within a RRIP enhanced ISO 9660 image the format is additionally marked
by a System Use entry with signature "ZF".
The uncompressed size of a single zisofs compressed file is restricted
to 4 GiB - 1. Larger files shall not be compressed.
File Header
The file header has this layout (quoted from zisofs-tools-1.0.8/mkzftree.c):
Byte offset iso9660 type Contents
0 (8 bytes) Magic number (37 E4 53 96 C9 DB D6 07)
8 7.3.1 Uncompressed file size
12 7.1.1 header_size >> 2 (currently 4)
13 7.1.1 log2(block_size)
14 (2 bytes) Reserved, must be zero
So its size is 16.
7.3.1 means little endian 4-byte words. 7.1.1. means unsigned single bytes.
Readers shall be able to handle log2(block_size) values 15, 16 and 17
i.e. block sizes 32 kB, 64 kB, and 128 kB. Writers must not use other sizes.
Block Pointers
There are ceil(input_size / block_size) input resp. output blocks.
Each input block is of fixed size whereas the output blocks have varying
size (down to 0). For each output block there is an offset pointer giving
its byte address in the overall file content. The next block pointer in the
array tells the start of the next block which begins immediately after the
end of its predecessor. A final pointer gives the first invalid byte address
and thus marks the end of the last block.
So there are ceil(input_size / block_size) + 1 block pointers.
They are stored as an array of 4-byte values which are in ISO 9660:7.3.1 format
directly after the file header, i.e. beginning at byte 16.
Data Part
The data part begins immediately after the pointer array. In principle it
consists of the variable length output blocks as delivered by zlib function
compress2() when fed with the fixed size input blocks.
A special case of input and output block is defined:
Zero-length blocks represent a block full of 0-bytes.
Such input blocks do not get processed by compress2() but shall be mapped to
0-sized output directly. Vice versa 0-sized blocks have to bypass uncompress()
when being read.
ZF System Use Entry Format
ZF may only be applied to files with a single extent and less than 4 GiB of
uncompressed size.
The ZF entry follows the general layout of SUSP resp. RRIP.
Its fields are:
[1] "BP 1 to BP 2 - Signature Word" shall be (5A)(46) ("ZF").
[2] "BP 3 - Length" shall specify as an 8-bit number the length in bytes of
the ZF entry recorded according to ISO 9660:7.1.1.
This length is 16 decimal.
[3] "BP 4 - System Use Entry Version" shall be 1 as in ISO 9660:7.1.1.
[4] "BP 5 to BP 6 - Algorithm" shall be (70)(7A) ("pz") to indicate
"paged zlib".
[5] "BP 7 - Header Size Div 4" shall specify as an 8-bit number the number of
4-byte words in the header part of the file data recorded according
to ISO 9660:7.1.1.
(This is a copy of header byte 12, resp. header BP 13).
[6] "BP 8 - Log2 of Block Size" shall specify as an 8-bit number the binary
logarithm of the compression block size recorded according to
ISO 9660:7.1.1.
(This is a copy of header byte 13, resp. header BP 14.
The value has to be 15, 16 or 17 i.e. 32 kiB, 64 kiB, or 128 kiB.)
[7] "BP 9 to BP 16 - Uncompressed Size" shall tell the number of uncompressed
bytes represented by the given extent. This field shall be recorded
according to ISO 9660:7.3.3.
(This number is the same as in header bytes 8 to 11, resp header BP 9
to BP 12.)
| 'Z' | 'F' | LENGTH | 1 | 'p' | 'z' | HEADER SIZE DIV 4 | LOG2 BLOCK SIZE
| UNCOMPRESSED SIZE |
ISO 9660:7.3.3 means 4-byte word in both byte orders, first little endian, then
big endian.
Example (block size 32 kiB, uncompressed file size = 1,234,567 bytes):
{ 'Z', "F', 16, 1, 'p', 'z', 4, 15,
0x87, 0xD6, 0x12, 0x00, 0x00, 0x12, 0xD6, 0x87 }
-------------------------------------------------------------------------------
Revoked specification aspects:
A comment in zisofs-tools-1.0.8 indicates a special case of output block:
"a block the length of which is equal to the block size is unencoded."
This is not implemented in zisofs-tools and in the Linux kernel. Existing
zisofs enhanced ISO images might contain encoded blocks which could be
mistaken for unencoded blocks.
Therefore this rule is not part of this description and must not be
implemented.
-------------------------------------------------------------------------------
References:
zisofs-tools
http://freshmeat.net/projects/zisofs-tools/
zlib:
/usr/include/zlib.h
cdrtools with mkisofs
ftp://ftp.berlios.de/pub/cdrecord/alpha
ECMA-119 aka ISO 9660
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
SUSP 1.12
ftp://ftp.ymi.com/pub/rockridge/susp112.ps
RRIP 1.12
ftp://ftp.ymi.com/pub/rockridge/rrip112.ps

96
libisofs/aaip-os-dummy.c Normal file
View File

@ -0,0 +1,96 @@
/*
aaip-os-dummy.c
Idle placeholder for:
Arbitrary Attribute Interchange Protocol , system adapter for getting and
setting of ACLs and xattr.
See aaip-os-linux.c for a real implementation of this interface.
To be included by aaip_0_2.c
Copyright (c) 2009 Thomas Schmitt, libburnia project, GPLv2
*/
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
/* ------------------------------ Getters --------------------------------- */
/* Obtain the ACL of the given file in long text form.
@return 0 ACL support not enabled at compile time
*/
int aaip_get_acl_text(char *path, char **text, int flag)
{
return(0);
}
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
that is ready for aaip_encode().
@return 1 ok
*/
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
size_t **value_lengths, char ***values, int flag)
{
*num_attrs= 0;
*names= NULL;
*value_lengths= NULL;
*values= NULL;
return(1);
}
/* ------------------------------ Setters --------------------------------- */
/* Set the ACL of the given file to a given list in long text form.
@return 0 ACL support not enabled at compile time
*/
int aaip_set_acl_text(char *path, char *text, int flag)
{
return(0);
}
/* Bring the given attributes and/or ACLs into effect with the given file.
@param flag Bitfield for control purposes
bit0= decode and set ACLs
bit1= first clear all existing attributes of the file
bit2= do not set attributes other than ACLs
@return 1 success (there was nothing to do)
-6 support of xattr not enabled at compile time
-7 support of ACL not enabled at compile time
*/
int aaip_set_attr_list(char *path, size_t num_attrs, char **names,
size_t *value_lengths, char **values, int flag)
{
size_t i;
for(i= 0; i < num_attrs; i++) {
if(names[i] == NULL || values[i] == NULL)
continue;
if(names[i][0] == 0) { /* ACLs */
if(flag & 1)
return(-7);
continue;
}
/* Extended Attribute */
if(!(flag & 4))
return(-6);
}
if(flag & 2)
return(-6);
return(1);
}

382
libisofs/aaip-os-freebsd.c Normal file
View File

@ -0,0 +1,382 @@
/*
aaip-os-freebsd.c
Arbitrary Attribute Interchange Protocol , system adapter for getting and
setting of ACLs and ixattr.
To be included by aaip_0_2.c
Copyright (c) 2009 Thomas Schmitt, libburnia project, GPLv2
*/
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#ifndef Libisofs_with_aaip_acL
/* It seems ACL is fixely integrated in FreeBSD libc. There is no libacl. */
#define Libisofs_with_aaip_acL yes
#endif
#ifdef Libisofs_with_aaip_acL
#include <sys/acl.h>
#endif
/* ------------------------------ Getters --------------------------------- */
/* Obtain the ACL of the given file in long text form.
@param path Path to the file
@param text Will hold the result. This is a managed object which
finally has to be freed by a call to this function
with bit15 of flag.
@param flag Bitfield for control purposes
bit0= obtain default ACL rather than access ACL
bit4= set *text = NULL and return 2
if the ACL matches st_mode permissions.
bit5= in case of symbolic link: inquire link target
bit15= free text and return 1
@return > 0 ok
0 ACL support not enabled at compile time
-1 failure of system ACL service (see errno)
-2 attempt to inquire ACL of a symbolic
link without bit4 or bit5
*/
int aaip_get_acl_text(char *path, char **text, int flag)
{
#ifdef Libisofs_with_aaip_acL
acl_t acl= NULL;
#endif
struct stat stbuf;
int ret;
if(flag & (1 << 15)) {
if(*text != NULL)
#ifdef Libisofs_with_aaip_acL
acl_free(*text);
#else
free(*text);
#endif
*text= NULL;
return(1);
}
*text= NULL;
if(flag & 32)
ret= stat(path, &stbuf);
else
ret= lstat(path, &stbuf);
if(ret == -1)
return(-1);
if((stbuf.st_mode & S_IFMT) == S_IFLNK) {
if(flag & 16)
return(2);
return(-2);
}
/* Note: no ACL_TYPE_DEFAULT in FreeBSD */
if(flag & 1)
return(0);
#ifdef Libisofs_with_aaip_acL
acl= acl_get_file(path, ACL_TYPE_ACCESS);
if(acl == NULL)
return(-1);
*text= acl_to_text(acl, NULL);
acl_free(acl);
#else /* Libisofs_with_aaip_acL */
/* ??? >>> Fake ACL */;
return(0);
#endif /* ! Libisofs_with_aaip_acL */
if(*text == NULL)
return(-1);
if(flag & 16) {
ret = aaip_cleanout_st_mode(*text, &(stbuf.st_mode), 2);
if(!(ret & (7 | 64)))
(*text)[0]= 0;
if((*text)[0] == 0 || strcmp(*text, "\n") == 0) {
#ifdef Libisofs_with_aaip_acL
acl_free(*text);
#else
free(*text);
#endif
*text= NULL;
return(2);
}
}
return(1);
}
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
that is ready for aaip_encode().
Note: There are no Extended Attributes in FreeBSD. So only ACL will be
obtained.
@param path Path to the file
@param num_attrs Will return the number of name-value pairs
@param names Will return an array of pointers to 0-terminated names
@param value_lengths Will return an arry with the lenghts of values
@param values Will return an array of pointers to 8-bit values
@param flag Bitfield for control purposes
bit0= obtain ACL (access and eventually default)
bit1= use numeric ACL qualifiers rather than names
bit2= do not encode attributes other than ACL
bit3= -reserved-
bit4= do not return trivial ACL that matches st_mode
bit15= free memory of names, value_lengths, values
@return >0 ok
<=0 error
*/
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
size_t **value_lengths, char ***values, int flag)
{
int ret;
ssize_t i, num_names;
size_t a_acl_len= 0, acl_len= 0;
unsigned char *a_acl= NULL, *d_acl= NULL, *acl= NULL;
char *acl_text= NULL;
if(flag & (1 << 15)) { /* Free memory */
{ret= 1; goto ex;}
}
*num_attrs= 0;
*names= NULL;
*value_lengths= NULL;
*values= NULL;
num_names= 0;
if(flag & 1)
num_names++;
if(num_names == 0)
{ret= 1; goto ex;}
(*names)= calloc(num_names, sizeof(char *));
(*value_lengths)= calloc(num_names, sizeof(size_t));
(*values)= calloc(num_names, sizeof(char *));
if(*names == NULL || *value_lengths == NULL || *values == NULL)
{ret= -1; goto ex;}
for(i= 0; i < num_names; i++) {
(*names)[i]= NULL;
(*values)[i]= NULL;
(*value_lengths)[i]= 0;
}
#ifdef Libisofs_with_aaip_acL
if(flag & 1) { /* Obtain ACL */
/* access-ACL */
ret= aaip_get_acl_text(path, &acl_text, flag & (16 | 32));
if(ret <= 0)
goto ex;
if(ret == 2)
{ret= 1; goto ex;} /* empty ACL / only st_mode info was found in ACL */
ret= aaip_encode_acl(acl_text, (mode_t) 0, &a_acl_len, &a_acl, flag & 2);
if(ret <= 0)
goto ex;
aaip_get_acl_text("", &acl_text, 1 << 15); /* free */
/* Note: There are no default-ACL in FreeBSD */
/* Set as attribute with empty name */;
(*names)[*num_attrs]= strdup("");
if((*names)[*num_attrs] == NULL)
{ret= -1; goto ex;}
(*values)[*num_attrs]= (char *) acl;
(*value_lengths)[*num_attrs]= acl_len;
(*num_attrs)++;
}
#endif /* Libisofs_with_aaip_acL */
ret= 1;
ex:;
if(a_acl != NULL)
free(a_acl);
if(d_acl != NULL)
free(d_acl);
if(acl_text != NULL)
aaip_get_acl_text("", &acl_text, 1 << 15); /* free */
if(ret <= 0 || (flag & (1 << 15))) {
if(*names != NULL) {
for(i= 0; i < *num_attrs; i++)
free((*names)[i]);
free(*names);
}
*names= NULL;
if(*value_lengths != NULL)
free(*value_lengths);
*value_lengths= NULL;
if(*values != NULL) {
for(i= 0; i < *num_attrs; i++)
free((*values)[i]);
free(*values);
}
if(acl != NULL)
free(acl);
*values= NULL;
*num_attrs= 0;
}
return(ret);
}
/* ------------------------------ Setters --------------------------------- */
/* Set the ACL of the given file to a given list in long text form.
@param path Path to the file
@param text The input text (0 terminated, ACL long text form)
@param flag Bitfield for control purposes
bit0= set default ACL rather than access ACL
@return > 0 ok
-1 failure of system ACL service (see errno)
-2 ACL support not enabled at compile time
*/
int aaip_set_acl_text(char *path, char *text, int flag)
{
#ifdef Libisofs_with_aaip_acL
int ret;
acl_t acl= NULL;
struct stat stbuf;
if(flag & 32)
ret= stat(path, &stbuf);
else
ret= lstat(path, &stbuf);
if(ret == -1)
return(-1);
if((stbuf.st_mode & S_IFMT) == S_IFLNK)
return(-2);
acl= acl_from_text(text);
if(acl == NULL) {
ret= -1; goto ex;
}
/* Note: no ACL_TYPE_DEFAULT in FreeBSD */
if(flag & 1)
{ret= 0; goto ex;}
ret= acl_set_file(path, ACL_TYPE_ACCESS, acl);
if(ret == -1)
goto ex;
ret= 1;
ex:
if(acl != NULL)
acl_free(acl);
return(ret);
#else /* Libisofs_with_aaip_acL */
return(-2);
#endif /* ! Libisofs_with_aaip_acL */
}
/* Bring the given attributes and/or ACLs into effect with the given file.
Note: There are no Extended Attributes in FreeBSD. So only ACL get set.
@param flag Bitfield for control purposes
bit0= decode and set ACLs
( bit1= first clear all existing attributes of the file )
( bit2= do not set attributes other than ACLs )
@return 1 success
-1 error memory allocation
-2 error with decoding of ACL
-3 error with setting ACL
( -4 error with setting attribute )
( -5 error with deleting attribute )
-6 support of xattr not enabled at compile time
-7 support of ACL not enabled at compile time
*/
int aaip_set_attr_list(char *path, size_t num_attrs, char **names,
size_t *value_lengths, char **values, int flag)
{
int ret, has_default_acl= 0, was_xattr= 0;
size_t i, consumed, acl_text_fill;
char *acl_text= NULL, *list= NULL;
for(i= 0; i < num_attrs; i++) {
if(names[i] == NULL || values[i] == NULL)
continue;
if(names[i][0] == 0) { /* Decode ACLs */
/* access ACL */
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
&consumed, NULL, 0, &acl_text_fill, 1);
if(ret <= 0)
{ret= -2; goto ex;}
acl_text= calloc(acl_text_fill, 1);
if(acl_text == NULL)
{ret= -1; goto ex;}
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
&consumed, acl_text, acl_text_fill, &acl_text_fill, 0);
if(ret <= 0)
{ret= -2; goto ex;}
has_default_acl= (ret == 2);
#ifdef Libisofs_with_aaip_acL
ret= aaip_set_acl_text(path, acl_text, flag & 32);
if(ret <= 0)
{ret= -3; goto ex;}
#else
{ret= -7; goto ex;}
#endif
/* "default" ACL */
if(has_default_acl) {
free(acl_text);
acl_text= NULL;
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
value_lengths[i] - consumed, &consumed,
NULL, 0, &acl_text_fill, 1);
if(ret <= 0)
{ret= -2; goto ex;}
acl_text= calloc(acl_text_fill, 1);
if(acl_text == NULL)
{ret= -1; goto ex;}
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
value_lengths[i] - consumed, &consumed,
acl_text, acl_text_fill, &acl_text_fill, 0);
if(ret <= 0)
{ret= -2; goto ex;}
ret= aaip_set_acl_text(path, acl_text, 1 | (flag & 32));
if(ret <= 0)
{ret= -3; goto ex;}
}
} else
was_xattr= 1;
}
ret= 1;
if(was_xattr)
ret= -6;
ex:;
if(acl_text != NULL)
free(acl_text);
if(list != NULL)
free(list);
return(ret);
}

500
libisofs/aaip-os-linux.c Normal file
View File

@ -0,0 +1,500 @@
/*
aaip-os-linux.c
Arbitrary Attribute Interchange Protocol , system adapter for getting and
setting of ACLs and xattr.
To be included by aaip_0_2.c
Copyright (c) 2009 Thomas Schmitt, libburnia project, GPLv2
*/
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#ifdef Libisofs_with_aaip_acL
#include <sys/acl.h>
#endif
#ifdef Libisofs_with_aaip_xattR
#include <attr/xattr.h>
#endif
/* ------------------------------ Getters --------------------------------- */
/* Obtain the ACL of the given file in long text form.
@param path Path to the file
@param text Will hold the result. This is a managed object which
finally has to be freed by a call to this function
with bit15 of flag.
@param flag Bitfield for control purposes
bit0= obtain default ACL rather than access ACL
behave like bit4 if ACL is empty
bit4= set *text = NULL and return 2
if the ACL matches st_mode permissions.
bit5= in case of symbolic link: inquire link target
bit15= free text and return 1
@return 1 ok
2 only st_mode permissions exist and bit 4 is set
or empty ACL and bit0 is set
0 ACL support not enabled at compile time
-1 failure of system ACL service (see errno)
-2 attempt to inquire ACL of a symbolic link without
bit4 or bit5 resp. with no suitable link target
*/
int aaip_get_acl_text(char *path, char **text, int flag)
{
#ifdef Libisofs_with_aaip_acL
acl_t acl= NULL;
struct stat stbuf;
int ret;
if(flag & (1 << 15)) {
if(*text != NULL)
acl_free(*text);
*text= NULL;
return(1);
}
*text= NULL;
if(flag & 32)
ret= stat(path, &stbuf);
else
ret= lstat(path, &stbuf);
if(ret == -1)
return(-1);
if((stbuf.st_mode & S_IFMT) == S_IFLNK) {
if(flag & 16)
return(2);
return(-2);
}
acl= acl_get_file(path, (flag & 1) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS);
if(acl == NULL)
return(-1);
*text= acl_to_text(acl, NULL);
acl_free(acl);
if(*text == NULL)
return(-1);
if(flag & 16) {
ret = aaip_cleanout_st_mode(*text, &(stbuf.st_mode), 2);
if(!(ret & (7 | 64)))
(*text)[0]= 0;
}
if(flag & (1 | 16)) {
if((*text)[0] == 0 || strcmp(*text, "\n") == 0) {
acl_free(*text);
*text= NULL;
return(2);
}
}
return(1);
#else /* Libisofs_with_aaip_acL */
return(0);
#endif /* ! Libisofs_with_aaip_acL */
}
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form
that is ready for aaip_encode().
@param path Path to the file
@param num_attrs Will return the number of name-value pairs
@param names Will return an array of pointers to 0-terminated names
@param value_lengths Will return an arry with the lenghts of values
@param values Will return an array of pointers to 8-bit values
@param flag Bitfield for control purposes
bit0= obtain ACL (access and eventually default)
bit1= use numeric ACL qualifiers rather than names
bit2= do not obtain attributes other than ACL
bit3= do not ignore eventual non-user attributes
I.e. those with a name which does not begin
by "user."
bit4= do not return trivial ACL that matches st_mode
bit5= in case of symbolic link: inquire link target
bit15= free memory of names, value_lengths, values
@return >0 ok
<=0 error
*/
int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names,
size_t **value_lengths, char ***values, int flag)
{
int ret, retry= 0;
char *list= NULL;
ssize_t list_size= 0, i, num_names= 0, value_ret;
size_t acl_len= 0;
unsigned char *acl= NULL;
char *a_acl_text= NULL, *d_acl_text= NULL;
if(flag & (1 << 15)) { /* Free memory */
{ret= 1; goto ex;}
}
*num_attrs= 0;
*names= NULL;
*value_lengths= NULL;
*values= NULL;
/* Set up arrays */
if(!(flag & 4)) { /* Get xattr names */
#ifdef Libisofs_with_aaip_xattR
if(flag & 32)
list_size= listxattr(path, list, 0);
else
list_size= llistxattr(path, list, 0);
if(list_size == -1)
{ret= -1; goto ex;}
list= calloc(list_size, 1);
if(list == NULL)
{ret= -1; goto ex;}
if(flag & 32)
list_size= listxattr(path, list, list_size);
else
list_size= llistxattr(path, list, list_size);
if(list_size == -1)
{ret= -1; goto ex;}
#else /* Libisofs_with_aaip_xattR */
list= strdup("");
#endif /* ! Libisofs_with_aaip_xattR */
for(i= 0; i < list_size; i+= strlen(list + i) + 1)
num_names++;
}
#ifdef Libisofs_with_aaip_acL
if(flag & 1)
num_names++;
#endif
if(num_names == 0)
{ret= 1; goto ex;}
(*names)= calloc(num_names, sizeof(char *));
(*value_lengths)= calloc(num_names, sizeof(size_t));
(*values)= calloc(num_names, sizeof(char *));
if(*names == NULL || *value_lengths == NULL || *values == NULL)
{ret= -1; goto ex;}
for(i= 0; i < num_names; i++) {
(*names)[i]= NULL;
(*values)[i]= NULL;
(*value_lengths)[i]= 0;
}
if(!(flag & 4)) {
for(i= 0; i < list_size && num_names > *num_attrs;
i+= strlen(list + i) + 1) {
if(!(flag & 8))
if(strncmp(list + i, "user.", 5))
continue;
(*names)[(*num_attrs)++]= strdup(list + i);
if((*names)[(*num_attrs) - 1] == NULL)
{ret= -1; goto ex;}
}
}
#ifdef Libisofs_with_aaip_xattR
if(!(flag & 4)) { /* Get xattr values */
for(i= 0; i < *num_attrs; i++) {
if(!(flag & 8))
if(strncmp((*names)[i], "user.", 5))
continue;
if(flag & 32)
value_ret= getxattr(path, (*names)[i], NULL, 0);
else
value_ret= lgetxattr(path, (*names)[i], NULL, 0);
if(value_ret == -1)
continue;
(*values)[i]= calloc(value_ret + 1, 1);
if((*values)[i] == NULL)
{ret= -1; goto ex;}
if(flag & 32)
value_ret= getxattr(path, (*names)[i], (*values)[i], value_ret);
else
value_ret= lgetxattr(path, (*names)[i], (*values)[i], value_ret);
if(value_ret == -1) { /* there could be a race condition */
if(retry++ > 5)
{ret= -1; goto ex;}
i--;
continue;
}
(*value_lengths)[i]= value_ret;
retry= 0;
}
}
#endif /* Libisofs_with_aaip_xattR */
#ifdef Libisofs_with_aaip_acL
if(flag & 1) { /* Obtain ACL */
aaip_get_acl_text(path, &a_acl_text, flag & (16 | 32));
aaip_get_acl_text(path, &d_acl_text, 1 | (flag & 32));
if(a_acl_text == NULL && d_acl_text == NULL)
{ret= 1; goto ex;}
ret= aaip_encode_both_acl(a_acl_text, d_acl_text, (mode_t) 0,
&acl_len, &acl, (flag & 2));
if(ret <= 0)
goto ex;
/* Set as attribute with empty name */;
(*names)[*num_attrs]= strdup("");
if((*names)[*num_attrs] == NULL)
{ret= -1; goto ex;}
(*values)[*num_attrs]= (char *) acl;
acl= NULL;
(*value_lengths)[*num_attrs]= acl_len;
(*num_attrs)++;
}
#endif /* Libisofs_with_aaip_acL */
ret= 1;
ex:;
if(a_acl_text != NULL)
aaip_get_acl_text("", &a_acl_text, 1 << 15); /* free */
if(d_acl_text != NULL)
aaip_get_acl_text("", &d_acl_text, 1 << 15); /* free */
if(ret <= 0 || (flag & (1 << 15))) {
if(list != NULL)
free(list);
if(*names != NULL) {
for(i= 0; i < *num_attrs; i++)
free((*names)[i]);
free(*names);
}
*names= NULL;
if(*value_lengths != NULL)
free(*value_lengths);
*value_lengths= NULL;
if(*values != NULL) {
for(i= 0; i < *num_attrs; i++)
free((*values)[i]);
free(*values);
}
if(acl != NULL)
free(acl);
*values= NULL;
*num_attrs= 0;
}
return(ret);
}
/* ------------------------------ Setters --------------------------------- */
/* Set the ACL of the given file to a given list in long text form.
@param path Path to the file
@param text The input text (0 terminated, ACL long text form)
@param flag Bitfield for control purposes
bit0= set default ACL rather than access ACL
bit5= in case of symbolic link: manipulate link target
@return >0 ok
0 ACL support not enabled at compile time
-1 failure of system ACL service (see errno)
-2 attempt to manipulate ACL of a symbolic link
without bit5 resp. with no suitable link target
*/
int aaip_set_acl_text(char *path, char *text, int flag)
{
#ifdef Libisofs_with_aaip_acL
int ret;
acl_t acl= NULL;
struct stat stbuf;
if(flag & 32)
ret= stat(path, &stbuf);
else
ret= lstat(path, &stbuf);
if(ret == -1)
return(-1);
if((stbuf.st_mode & S_IFMT) == S_IFLNK)
return(-2);
acl= acl_from_text(text);
if(acl == NULL) {
ret= -1; goto ex;
}
ret= acl_set_file(path, (flag & 1) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS, acl);
if(ret == -1)
goto ex;
ret= 1;
ex:
if(acl != NULL)
acl_free(acl);
return(ret);
#else /* Libisofs_with_aaip_acL */
return(0);
#endif /* ! Libisofs_with_aaip_acL */
}
/* Bring the given attributes and/or ACLs into effect with the given file.
@param flag Bitfield for control purposes
bit0= decode and set ACLs
bit1= first clear all existing attributes of the file
bit2= do not set attributes other than ACLs
bit3= do not ignore eventual non-user attributes.
I.e. those with a name which does not begin
by "user."
bit5= in case of symbolic link: manipulate link target
@return 1 success
-1 error memory allocation
-2 error with decoding of ACL
-3 error with setting ACL
-4 error with setting attribute
-5 error with deleting attributes
-6 support of xattr not enabled at compile time
-7 support of ACL not enabled at compile time
*/
int aaip_set_attr_list(char *path, size_t num_attrs, char **names,
size_t *value_lengths, char **values, int flag)
{
int ret, has_default_acl= 0;
size_t i, consumed, acl_text_fill, list_size= 0, acl_idx= 0, h_consumed;
char *acl_text= NULL, *list= NULL;
#ifdef Libisofs_with_aaip_xattR
if(flag & 2) { /* Delete all file attributes */
if(flag & 32)
list_size= listxattr(path, list, 0);
else
list_size= llistxattr(path, list, 0);
}
if(list_size > 0) { /* Delete all file attributes */
list= calloc(list_size, 1);
if(list == NULL)
{ret= -5; goto ex;}
if(flag & 32)
list_size= listxattr(path, list, list_size);
else
list_size= llistxattr(path, list, list_size);
if(list_size == -1)
{ret= -5; goto ex;}
for(i= 0; i < list_size; i+= strlen(list + i) + 1) {
if(!(flag & 8))
if(strncmp(list + i, "user.", 5))
continue;
if(flag & 32)
ret= removexattr(path, list + i);
else
ret= lremovexattr(path, list + i);
if(ret == -1)
{ret= -5; goto ex;}
}
free(list); list= NULL;
}
#endif /* Libisofs_with_aaip_xattR */
for(i= 0; i < num_attrs; i++) {
if(names[i] == NULL || values[i] == NULL)
continue;
if(names[i][0] == 0) { /* ACLs */
if(flag & 1)
acl_idx= i + 1;
continue;
}
/* Extended Attribute */
if((flag & 1) && !(flag & 8))
if(strncmp(names[i], "user.", 5))
continue;
#ifdef Libisofs_with_aaip_xattR
if(flag & 32)
ret= setxattr(path, names[i], values[i], value_lengths[i], 0);
else
ret= lsetxattr(path, names[i], values[i], value_lengths[i], 0);
if(ret == -1)
{ret= -4; goto ex;}
#else
{ret= -6; goto ex;}
#endif /* Libisofs_with_aaip_xattR */
}
/* Decode ACLs */
if(acl_idx == 0)
{ret= 1; goto ex;}
i= acl_idx - 1;
/* "access" ACL */
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
&consumed, NULL, 0, &acl_text_fill, 1);
if(ret <= 0)
{ret= -2; goto ex;}
acl_text= calloc(acl_text_fill, 1);
if(acl_text == NULL)
{ret= -1; goto ex;}
ret= aaip_decode_acl((unsigned char *) values[i], value_lengths[i],
&consumed, acl_text, acl_text_fill, &acl_text_fill, 0);
if(ret <= 0)
{ret= -2; goto ex;}
has_default_acl= (ret == 2);
#ifdef Libisofs_with_aaip_acL
ret= aaip_set_acl_text(path, acl_text, flag & 32);
if(ret <= 0)
{ret= -3; goto ex;}
#else
{ret= -7; goto ex;}
#endif
/* "default" ACL */
if(has_default_acl) {
free(acl_text);
acl_text= NULL;
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
value_lengths[i] - consumed, &h_consumed,
NULL, 0, &acl_text_fill, 1);
if(ret <= 0)
{ret= -2; goto ex;}
acl_text= calloc(acl_text_fill, 1);
if(acl_text == NULL)
{ret= -1; goto ex;}
ret= aaip_decode_acl((unsigned char *) (values[i] + consumed),
value_lengths[i] - consumed, &h_consumed,
acl_text, acl_text_fill, &acl_text_fill, 0);
if(ret <= 0)
{ret= -2; goto ex;}
ret= aaip_set_acl_text(path, acl_text, 1 | (flag & 32));
if(ret <= 0)
{ret= -3; goto ex;}
}
ret= 1;
ex:;
if(acl_text != NULL)
free(acl_text);
if(list != NULL)
free(list);
return(ret);
}

2138
libisofs/aaip_0_2.c Normal file

File diff suppressed because it is too large Load Diff

486
libisofs/aaip_0_2.h Normal file
View 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 */

View File

@ -1,23 +1,28 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/*
* Synchronized ring buffer, works with a writer thread and a read thread.
*
*
* TODO #00010 : optimize ring buffer
* - write/read at the end of buffer requires a second mutex_lock, even if
* there's enought space/data at the beginning
* - pre-buffer for writes < BLOCK_SIZE
*
*
*/
/*
Use the copy of the struct burn_source definition in libisofs.h
*/
#define LIBISOFS_WITHOUT_LIBBURN yes
#include "libisofs.h"
#include "buffer.h"
#include "libburn/libburn.h"
#include "ecma119.h"
#include <pthread.h>
@ -30,13 +35,13 @@
struct iso_ring_buffer
{
uint8_t *buf;
/*
* Max number of bytes in buffer
*/
size_t cap;
/*
/*
* Number of bytes available.
*/
size_t size;
@ -45,11 +50,11 @@ struct iso_ring_buffer
size_t rpos;
size_t wpos;
/*
/*
* flags to report if read or writer threads ends execution
* 0 not finished, 1 finished ok, 2 finish with error
* 0 not finished, 1 finished ok, 2 finish with error
*/
unsigned int rend :2;
unsigned int rend :2;
unsigned int wend :2;
/* just for statistical purposes */
@ -63,9 +68,9 @@ struct iso_ring_buffer
/**
* Create a new buffer.
*
*
* The created buffer should be freed with iso_ring_buffer_free()
*
*
* @param size
* Number of blocks in buffer. You should supply a number >= 32, otherwise
* size will be ignored and 32 will be used by default, which leads to a
@ -85,14 +90,14 @@ int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf)
if (buffer == NULL) {
return ISO_OUT_OF_MEM;
}
buffer->cap = (size > 32 ? size : 32) * BLOCK_SIZE;
buffer->buf = malloc(buffer->cap);
if (buffer->buf == NULL) {
free(buffer);
return ISO_OUT_OF_MEM;
}
buffer->size = 0;
buffer->wpos = 0;
buffer->rpos = 0;
@ -126,7 +131,7 @@ void iso_ring_buffer_free(IsoRingBuffer *buf)
/**
* Write count bytes into buffer. It blocks until all bytes where written or
* reader close the buffer.
*
*
* @param buf
* the buffer
* @param data
@ -189,7 +194,7 @@ int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count)
* bytes has been read. If the writer finishes before outputting enought
* bytes, 0 (EOF) is returned, the number of bytes already read remains
* unknown.
*
*
* @return
* 1 success, 0 EOF, < 0 error
*/
@ -252,7 +257,7 @@ void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error)
void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error)
{
pthread_mutex_lock(&buf->mutex);
if (buf->rend) {
/* reader already closed */
pthread_mutex_unlock(&buf->mutex);
@ -285,9 +290,9 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
/**
* Get the status of the buffer used by a burn_source.
*
*
* @param b
* A burn_source previously obtained with
* A burn_source previously obtained with
* iso_image_create_burn_source().
* @param size
* Will be filled with the total size of the buffer, in bytes
@ -302,7 +307,7 @@ unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
* 6="ended" : consumption has ended without input error
* 7="aborted" : consumption has ended after input error
*/
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
size_t *free_bytes)
{
int ret;
@ -311,7 +316,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
return ISO_NULL_POINTER;
}
buf = ((Ecma119Image*)(b->data))->buffer;
/* get mutex */
pthread_mutex_lock(&buf->mutex);
if (size) {
@ -322,7 +327,7 @@ int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
}
ret = (buf->rend ? 4 : 0) + (buf->wend + 1);
pthread_mutex_unlock(&buf->mutex);
return ret;
}

View File

@ -1,19 +1,27 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/* libisofs.h defines aaip_xinfo_func */
#include "libisofs.h"
#include "builder.h"
#include "node.h"
#include "fsource.h"
#include "image.h"
#include "aaip_0_2.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
void iso_node_builder_ref(IsoNodeBuilder *builder)
{
++builder->refcount;
@ -52,12 +60,13 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
if (ret < 0) {
return ret;
}
/* take a ref to the src, as stream has taken our ref */
iso_file_source_ref(src);
name = iso_file_source_get_name(src);
ret = iso_node_new_file(name, stream, &node);
if (ret < 0) {
/* the stream has taken our ref to src, so we need to add one */
iso_file_source_ref(src);
iso_stream_unref(stream);
free(name);
return ret;
@ -83,7 +92,10 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
int ret;
struct stat info;
IsoNode *new;
IsoFilesystem *fs;
char *name;
unsigned char *aa_string;
char *a_text = NULL, *d_text = NULL;
if (builder == NULL || src == NULL || node == NULL) {
return ISO_NULL_POINTER;
@ -100,6 +112,7 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
}
name = iso_file_source_get_name(src);
fs = iso_file_source_get_filesystem(src);
new = NULL;
switch (info.st_mode & S_IFMT) {
@ -143,6 +156,13 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
}
ret = iso_node_new_symlink(name, strdup(dest), &link);
new = (IsoNode*) link;
if (fs != NULL) {
link->fs_id = fs->get_id(fs);
if (link->fs_id != 0) {
link->st_ino = info.st_ino;
link->st_dev = info.st_dev;
}
}
}
break;
case S_IFSOCK:
@ -155,6 +175,13 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
ret = iso_node_new_special(name, info.st_mode, info.st_rdev,
&special);
new = (IsoNode*) special;
if (fs != NULL) {
special->fs_id = fs->get_id(fs);
if (special->fs_id != 0) {
special->st_ino = info.st_ino;
special->st_dev = info.st_dev;
}
}
}
break;
}
@ -165,7 +192,7 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
}
/* fill fields */
iso_node_set_permissions(new, info.st_mode);
iso_node_set_perms_internal(new, info.st_mode, 1);
iso_node_set_uid(new, info.st_uid);
iso_node_set_gid(new, info.st_gid);
iso_node_set_atime(new, info.st_atime);
@ -173,7 +200,31 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
iso_node_set_ctime(new, info.st_ctime);
iso_node_set_uid(new, info.st_uid);
/* Eventually set S_IRWXG from ACL */
if (image->builder_ignore_acl) {
ret = iso_file_source_get_aa_string(src, &aa_string, 4);
if (aa_string != NULL)
iso_aa_get_acl_text(aa_string, info.st_mode, &a_text, &d_text, 16);
if (a_text != NULL) {
aaip_cleanout_st_mode(a_text, &(info.st_mode), 4 | 16);
iso_node_set_perms_internal(new, info.st_mode, 1);
}
iso_aa_get_acl_text(aa_string, info.st_mode, &a_text, &d_text,
1 << 15); /* free ACL texts */
}
/* Obtain ownership of eventual AAIP string */
ret = iso_file_source_get_aa_string(src, &aa_string,
1 | (image->builder_ignore_acl << 1) |
(image->builder_ignore_ea << 2 ));
if (ret == 1 && aa_string != NULL) {
ret = iso_node_add_xinfo(new, aaip_xinfo_func, aa_string);
if (ret < 0)
return ret;
}
*node = new;
return ISO_SUCCESS;
}

View File

@ -34,8 +34,7 @@ struct Iso_Node_Builder
* In that case, if the implementation can't do the conversion, it
* should fail propertly.
*
* On sucess, the ref. to src will be owned by file, so you musn't
* unref it.
* Note that the src is never unref, so you need to free it.
*
* @return
* 1 on success, < 0 on error

View File

@ -57,7 +57,7 @@ int ds_open(IsoDataSource *src)
data = (struct file_data_src*) src->data;
if (data->fd != -1) {
return ISO_FILE_ALREADY_OPENNED;
return ISO_FILE_ALREADY_OPENED;
}
fd = open(data->path, O_RDONLY);
@ -81,7 +81,7 @@ int ds_close(IsoDataSource *src)
data = (struct file_data_src*) src->data;
if (data->fd == -1) {
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
/* close can fail if fd is not valid, but that should never happen */
@ -102,7 +102,7 @@ static int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
data = (struct file_data_src*) src->data;
if (data->fd == -1) {
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
/* goes to requested block */

View File

@ -1,13 +1,19 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2007 Mario Danic
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/*
Use the copy of the struct burn_source definition in libisofs.h
*/
#define LIBISOFS_WITHOUT_LIBBURN yes
#include "libisofs.h"
#include "ecma119.h"
#include "joliet.h"
#include "iso1999.h"
@ -19,8 +25,7 @@
#include "messages.h"
#include "rockridge.h"
#include "util.h"
#include "libburn/libburn.h"
#include "system_area.h"
#include <stdlib.h>
#include <time.h>
@ -90,10 +95,10 @@ size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n)
/**
* Computes the total size of all directory entries of a single dir,
* acording to ECMA-119 6.8.1.1
*
*
* This also take into account the size needed for RR entries and
* SUSP continuation areas (SUSP, 5.1).
*
*
* @param ce
* Will be filled with the size needed for Continuation Areas
* @return
@ -117,24 +122,29 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
for (i = 0; i < dir->info.dir->nchildren; ++i) {
size_t remaining;
int section, nsections;
Ecma119Node *child = dir->info.dir->children[i];
size_t dirent_len = calc_dirent_len(t, child);
if (t->rockridge) {
dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
*ce += ce_len;
}
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
if (dirent_len > remaining) {
/* child directory entry doesn't fit on block */
len += remaining + dirent_len;
} else {
len += dirent_len;
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
size_t dirent_len = calc_dirent_len(t, child);
if (t->rockridge) {
dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
*ce += ce_len;
}
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
if (dirent_len > remaining) {
/* child directory entry doesn't fit on block */
len += remaining + dirent_len;
} else {
len += dirent_len;
}
}
}
/*
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* (ECMA-119, 6.8.1.3)
*/
len = ROUND_UP(len, BLOCK_SIZE);
@ -222,28 +232,31 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer)
/**
* Write a single directory record (ECMA-119, 9.1)
*
*
* @param file_id
* if >= 0, we use it instead of the filename (for "." and ".." entries).
* @param len_fi
* Computed length of the file identifier. Total size of the directory
* entry will be len + 33 + padding if needed (ECMA-119, 9.1.12)
* @param info
* SUSP entries for the given directory record. It will be NULL for the
* root directory record in the PVD (ECMA-119, 8.4.18) (in order to
* SUSP entries for the given directory record. It will be NULL for the
* root directory record in the PVD (ECMA-119, 8.4.18) (in order to
* distinguish it from the "." entry in the root directory)
*/
static
void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
uint8_t *buf, size_t len_fi, struct susp_info *info)
uint8_t *buf, size_t len_fi, struct susp_info *info,
int extent)
{
uint32_t len;
uint32_t block;
uint8_t len_dr; /*< size of dir entry without SUSP fields */
int multi_extend = 0;
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
: (uint8_t*)node->iso_name;
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
IsoNode *iso;
len_dr = 33 + len_fi + (len_fi % 2 ? 0 : 1);
@ -260,12 +273,13 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
len = node->info.dir->len;
block = node->info.dir->block;
} else if (node->type == ECMA119_FILE) {
len = iso_file_src_get_size(node->info.file);
block = node->info.file->block;
block = node->info.file->sections[extent].block;
len = node->info.file->sections[extent].size;
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
} else {
/*
* for nodes other than files and dirs, we set both
* len and block to 0
/*
* for nodes other than files and dirs, we set both
* len and block to 0
*/
len = 0;
block = 0;
@ -280,12 +294,21 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0);
iso_bb(rec->block, block, 4);
iso_bb(rec->length, len, 4);
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0;
if(t->dir_rec_mtime) {
iso= node->node;
iso_datetime_7(rec->recording_time,
t->replace_timestamps ? t->timestamp : iso->mtime,
t->always_gmt);
} else {
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
}
rec->flags[0] = ((node->type == ECMA119_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
iso_bb(rec->vol_seq_number, 1, 2);
rec->len_fi[0] = len_fi;
/* and finally write the SUSP fields */
/*
* and finally write the SUSP fields.
*/
if (info != NULL) {
rrip_write_susp_fields(t, info, buf + len_dr);
}
@ -306,8 +329,8 @@ char *get_relaxed_vol_id(Ecma119Image *t, const char *name)
return str;
}
iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
"Charset conversion error. Can't convert %s from %s to %s",
name, t->input_charset, t->output_charset);
"Charset conversion error. Cannot convert from %s to %s",
t->input_charset, t->output_charset);
}
return strdup(name);
}
@ -365,7 +388,7 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4);
iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4);
write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL);
write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL, 0);
strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
strncpy_pad((char*)vol.publisher_id, pub_id, 128);
@ -396,7 +419,7 @@ int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
}
static
int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
{
int ret;
uint8_t buffer[BLOCK_SIZE];
@ -410,14 +433,14 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
/* initialize buffer with 0s */
memset(buffer, 0, BLOCK_SIZE);
/*
/*
* set susp_info to 0's, this way code for both plain ECMA-119 and
* RR is very similar
*/
memset(&info, 0, sizeof(struct susp_info));
if (t->rockridge) {
/* initialize the ce_block, it might be needed */
info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
BLOCK_SIZE);
}
@ -429,7 +452,7 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
}
}
len = 34 + info.suf_len;
write_one_dir_record(t, dir, 0, buf, 1, &info);
write_one_dir_record(t, dir, 0, buf, 1, &info, 0);
buf += len;
if (t->rockridge) {
@ -439,40 +462,46 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
}
}
len = 34 + info.suf_len;
write_one_dir_record(t, dir, 1, buf, 1, &info);
write_one_dir_record(t, parent, 1, buf, 1, &info, 0);
buf += len;
for (i = 0; i < dir->info.dir->nchildren; i++) {
int section, nsections;
Ecma119Node *child = dir->info.dir->children[i];
/* compute len of directory entry */
fi_len = strlen(child->iso_name);
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
if (need_version_number(t, child)) {
len += 2;
}
/* get the SUSP fields if rockridge is enabled */
if (t->rockridge) {
ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
if (ret < 0) {
return ret;
}
len += info.suf_len;
}
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
if ( (buf + len - buffer) > BLOCK_SIZE) {
/* dir doesn't fit in current block */
ret = iso_write(t, buffer, BLOCK_SIZE);
if (ret < 0) {
return ret;
/* compute len of directory entry */
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
if (need_version_number(t, child)) {
len += 2;
}
memset(buffer, 0, BLOCK_SIZE);
buf = buffer;
/* get the SUSP fields if rockridge is enabled */
if (t->rockridge) {
ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
if (ret < 0) {
return ret;
}
len += info.suf_len;
}
if ( (buf + len - buffer) > BLOCK_SIZE) {
/* dir doesn't fit in current block */
ret = iso_write(t, buffer, BLOCK_SIZE);
if (ret < 0) {
return ret;
}
memset(buffer, 0, BLOCK_SIZE);
buf = buffer;
}
/* write the directory entry in any case */
write_one_dir_record(t, child, -1, buf, fi_len, &info, section);
buf += len;
}
/* write the directory entry in any case */
write_one_dir_record(t, child, -1, buf, fi_len, &info);
buf += len;
}
/* write the last block */
@ -490,13 +519,13 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
}
static
int write_dirs(Ecma119Image *t, Ecma119Node *root)
int write_dirs(Ecma119Image *t, Ecma119Node *root, Ecma119Node *parent)
{
int ret;
size_t i;
/* write all directory entries for this dir */
ret = write_one_dir(t, root);
ret = write_one_dir(t, root, parent);
if (ret < 0) {
return ret;
}
@ -505,7 +534,7 @@ int write_dirs(Ecma119Image *t, Ecma119Node *root)
for (i = 0; i < root->info.dir->nchildren; i++) {
Ecma119Node *child = root->info.dir->children[i];
if (child->type == ECMA119_DIR) {
ret = write_dirs(t, child);
ret = write_dirs(t, child, root);
if (ret < 0) {
return ret;
}
@ -624,7 +653,7 @@ int ecma119_writer_write_data(IsoImageWriter *writer)
t = writer->target;
/* first of all, we write the directory structure */
ret = write_dirs(t, t->root);
ret = write_dirs(t, t->root, t->root);
if (ret < 0) {
return ret;
}
@ -709,7 +738,7 @@ int pad_writer_write_data(IsoImageWriter *writer)
return ISO_ASSERT_FAILURE;
}
t = writer->target;
if (t->pad_blocks == 0) {
return ISO_SUCCESS;
}
@ -768,10 +797,14 @@ void *write_function(void *arg)
target->bytes_written = (off_t) 0;
target->percent_written = 0;
/* Write System Area, 16 blocks of zeros (ECMA-119, 6.2.1) */
memset(buf, 0, BLOCK_SIZE);
for (i = 0; i < 16; ++i) {
res = iso_write(target, buf, BLOCK_SIZE);
/* Write System Area (ECMA-119, 6.2.1) */
{
uint8_t sa[16 * BLOCK_SIZE];
res = iso_write_system_area(target, sa);
if (res < 0) {
goto write_error;
}
res = iso_write(target, sa, 16 * BLOCK_SIZE);
if (res < 0) {
goto write_error;
}
@ -820,7 +853,7 @@ void *write_function(void *arg)
iso_msg_submit(target->image->id, ISO_IMAGE_WRITE_CANCELED, 0, NULL);
} else {
/* image write error */
iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res,
iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res,
"Image write error");
}
iso_ring_buffer_writer_close(target->buffer, 1);
@ -832,6 +865,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
{
int ret, i, voldesc_size, nwriters;
Ecma119Image *target;
int el_torito_writer_index = -1, file_src_writer_index= -1;
/* 1. Allocate target and copy opts there */
target = calloc(1, sizeof(Ecma119Image));
@ -853,9 +887,15 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
target->rockridge = opts->rockridge;
target->joliet = opts->joliet;
target->iso1999 = opts->iso1999;
target->hardlinks = opts->hardlinks;
target->aaip = opts->aaip;
target->always_gmt = opts->always_gmt;
#ifndef Libisofs_hardlink_matcheR
target->ino = 0;
target->omit_version_numbers = opts->omit_version_numbers
#endif
target->omit_version_numbers = opts->omit_version_numbers
| opts->max_37_char_filenames;
target->allow_deep_paths = opts->allow_deep_paths;
target->allow_longer_paths = opts->allow_longer_paths;
@ -865,6 +905,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
target->allow_full_ascii = opts->allow_full_ascii;
target->relaxed_vol_atts = opts->relaxed_vol_atts;
target->joliet_longer_paths = opts->joliet_longer_paths;
target->rrip_version_1_10 = opts->rrip_version_1_10;
target->rrip_1_10_px_ino = opts->rrip_1_10_px_ino;
target->aaip_susp_1_10 = opts->aaip_susp_1_10;
target->dir_rec_mtime = opts->dir_rec_mtime;
target->sort_files = opts->sort_files;
target->replace_uid = opts->replace_uid ? 1 : 0;
@ -882,16 +926,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
target->appendable = opts->appendable;
target->replace_timestamps = opts->replace_timestamps ? 1 : 0;
target->timestamp = opts->replace_timestamps == 2 ?
target->timestamp = opts->replace_timestamps == 2 ?
opts->timestamp : target->now;
/* el-torito? */
target->eltorito = (src->bootcat == NULL ? 0 : 1);
target->catalog = src->bootcat;
/* default to locale charset */
setlocale(LC_CTYPE, "");
target->input_charset = strdup(nl_langinfo(CODESET));
target->input_charset = strdup(iso_get_local_charset(0));
if (target->input_charset == NULL) {
iso_image_unref(src);
free(target);
@ -909,10 +951,10 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
return ISO_OUT_OF_MEM;
}
/*
/*
* 2. Based on those options, create needed writers: iso, joliet...
* Each writer inits its structures and stores needed info into
* target.
* target.
* If the writer needs an volume descriptor, it increments image
* current block.
* Finally, create Writer for files.
@ -944,15 +986,16 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
if (ret < 0) {
goto target_cleanup;
}
/* create writer for El-Torito */
if (target->eltorito) {
ret = eltorito_writer_create(target);
if (ret < 0) {
goto target_cleanup;
}
el_torito_writer_index = target->nwriters - 1;
}
/* create writer for Joliet structure */
if (target->joliet) {
ret = joliet_writer_create(target);
@ -960,7 +1003,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
goto target_cleanup;
}
}
/* create writer for ISO 9660:1999 structure */
if (target->iso1999) {
ret = iso1999_writer_create(target);
@ -970,11 +1013,11 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
}
voldesc_size = target->curblock - target->ms_block - 16;
/* Volume Descriptor Set Terminator */
target->curblock++;
/*
/*
* Create the writer for possible padding to ensure that in case of image
* growing we can safety overwrite the first 64 KiB of image.
*/
@ -988,20 +1031,44 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
if (ret < 0) {
goto target_cleanup;
}
file_src_writer_index = target->nwriters - 1;
/*
* 3.
* 3.
* Call compute_data_blocks() in each Writer.
* That function computes the size needed by its structures and
* increments image current block propertly.
*/
for (i = 0; i < target->nwriters; ++i) {
IsoImageWriter *writer = target->writers[i];
#define Libisofs_patch_ticket_145 yes
#ifdef Libisofs_patch_ticket_145
/* Delaying boot image patching until new LBA is known */
if (i == el_torito_writer_index)
continue;
#endif
/* Exposing address of data start to IsoWriteOpts */
if (i == file_src_writer_index) {
opts->data_start_lba = target->curblock;
}
ret = writer->compute_data_blocks(writer);
if (ret < 0) {
goto target_cleanup;
}
}
#ifdef Libisofs_patch_ticket_145
/* Now perform delayed image patching */
if (el_torito_writer_index >= 0) {
IsoImageWriter *writer = target->writers[el_torito_writer_index];
ret = writer->compute_data_blocks(writer);
if (ret < 0) {
goto target_cleanup;
}
}
#endif /* Libisofs_patch_ticket_145 */
/* create the ring buffer */
ret = iso_ring_buffer_new(opts->fifo_size, &target->buffer);
@ -1038,6 +1105,14 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
}
}
/* write the system area */
ret = iso_write_system_area(target, opts->overwrite);
if (ret < 0) {
iso_msg_debug(target->image->id,
"Error writing system area to overwrite buffer");
goto target_cleanup;
}
/* skip the first 16 blocks (system area) */
buf = opts->overwrite + 16 * BLOCK_SIZE;
voldesc_size *= BLOCK_SIZE;
@ -1130,14 +1205,14 @@ static void bs_free_data(struct burn_source *bs)
if (st < 4) {
/* forces writer to stop if it is still running */
iso_ring_buffer_reader_close(target->buffer, 0);
/* wait until writer thread finishes */
pthread_join(target->wthread, NULL);
iso_msg_debug(target->image->id, "Writer thread joined");
}
iso_msg_debug(target->image->id,
"Ring buffer was %d times full and %d times empty",
iso_msg_debug(target->image->id,
"Ring buffer was %d times full and %d times empty",
iso_ring_buffer_get_times_full(target->buffer),
iso_ring_buffer_get_times_empty(target->buffer));
@ -1153,9 +1228,9 @@ int bs_cancel(struct burn_source *bs)
Ecma119Image *target = (Ecma119Image*)bs->data;
st = iso_ring_buffer_get_status(bs, &cap, &free);
if (free == cap && (st == 2 || st == 3)) {
/* image was already consumed */
/* image was already consumed */
iso_ring_buffer_reader_close(target->buffer, 0);
} else {
iso_msg_debug(target->image->id, "Reader thread being cancelled");
@ -1176,7 +1251,7 @@ int bs_set_size(struct burn_source *bs, off_t size)
{
Ecma119Image *target = (Ecma119Image*)bs->data;
/*
/*
* just set the value to be returned by get_size. This is not used at
* all by libisofs, it is here just for helping libburn to correctly pad
* the image if needed.
@ -1235,12 +1310,12 @@ int iso_write(Ecma119Image *target, void *buf, size_t count)
if (ret > 0 && (target->total_size != (off_t) 0)){
unsigned int kbw, kbt;
int percent;
target->bytes_written += (off_t) count;
kbw = (unsigned int) (target->bytes_written >> 10);
kbt = (unsigned int) (target->total_size >> 10);
percent = (kbw * 100) / kbt;
/* only report in 5% chunks */
if (percent >= target->percent_written + 5) {
iso_msg_debug(target->image->id, "Processed %u of %u KB (%d %%)",
@ -1248,32 +1323,32 @@ int iso_write(Ecma119Image *target, void *buf, size_t count)
target->percent_written = percent;
}
}
return ret;
}
int iso_write_opts_new(IsoWriteOpts **opts, int profile)
{
IsoWriteOpts *wopts;
if (opts == NULL) {
return ISO_NULL_POINTER;
}
if (profile < 0 || profile > 2) {
return ISO_WRONG_ARG_VALUE;
}
wopts = calloc(1, sizeof(IsoWriteOpts));
if (wopts == NULL) {
return ISO_OUT_OF_MEM;
}
switch (profile) {
case 0:
wopts->level = 1;
break;
case 1:
wopts->level = 2;
wopts->level = 3;
wopts->rockridge = 1;
break;
case 2:
@ -1305,7 +1380,7 @@ void iso_write_opts_free(IsoWriteOpts *opts)
if (opts == NULL) {
return;
}
free(opts->output_charset);
free(opts);
}
@ -1315,7 +1390,7 @@ int iso_write_opts_set_iso_level(IsoWriteOpts *opts, int level)
if (opts == NULL) {
return ISO_NULL_POINTER;
}
if (level != 1 && level != 2) {
if (level != 1 && level != 2 && level != 3) {
return ISO_WRONG_ARG_VALUE;
}
opts->level = level;
@ -1349,6 +1424,24 @@ int iso_write_opts_set_iso1999(IsoWriteOpts *opts, int enable)
return ISO_SUCCESS;
}
int iso_write_opts_set_hardlinks(IsoWriteOpts *opts, int enable)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
opts->hardlinks = enable ? 1 : 0;
return ISO_SUCCESS;
}
int iso_write_opts_set_aaip(IsoWriteOpts *opts, int enable)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
opts->aaip = enable ? 1 : 0;
return ISO_SUCCESS;
}
int iso_write_opts_set_omit_version_numbers(IsoWriteOpts *opts, int omit)
{
if (opts == NULL) {
@ -1430,6 +1523,42 @@ int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow)
return ISO_SUCCESS;
}
int iso_write_opts_set_rrip_version_1_10(IsoWriteOpts *opts, int oldvers)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
opts->rrip_version_1_10 = oldvers ? 1 : 0;
return ISO_SUCCESS;
}
int iso_write_opts_set_rrip_1_10_px_ino(IsoWriteOpts *opts, int enable)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
opts->rrip_1_10_px_ino = enable ? 1 : 0;
return ISO_SUCCESS;
}
int iso_write_opts_set_aaip_susp_1_10(IsoWriteOpts *opts, int oldvers)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
opts->aaip_susp_1_10 = oldvers ? 1 : 0;
return ISO_SUCCESS;
}
int iso_write_opts_set_dir_rec_mtime(IsoWriteOpts *opts, int allow)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
opts->dir_rec_mtime = allow ? 1 : 0;
return ISO_SUCCESS;
}
int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort)
{
if (opts == NULL) {
@ -1577,3 +1706,13 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size)
opts->fifo_size = fifo_size;
return ISO_SUCCESS;
}
int iso_write_opts_get_data_start(IsoWriteOpts *opts, uint32_t *data_start,
int flag)
{
if(opts->data_start_lba == 0)
return ISO_ERROR;
*data_start = opts->data_start_lba;
return ISO_SUCCESS;
}

View File

@ -1,8 +1,9 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -18,6 +19,18 @@
#define BLOCK_SIZE 2048
/*
* Maximum file section size. Set to 4GB - 1 = 0xffffffff
*/
#define MAX_ISO_FILE_SECTION_SIZE 0xffffffff
/*
* When a file need to be splitted in several sections, the maximum size
* of such sections, but the last one. Set to a multiple of BLOCK_SIZE.
* Default to 4GB - 2048 = 0xFFFFF800
*/
#define ISO_EXTENT_SIZE 0xFFFFF800
/**
* Holds the options for the image generation.
*/
@ -30,14 +43,16 @@ struct iso_write_opts {
unsigned int joliet :1;
unsigned int iso1999 :1;
unsigned int aaip :1; /* whether to write eventual ACL and EAs */
/* allways write timestamps in GMT */
unsigned int always_gmt :1;
/*
/*
* Relaxed constraints. Setting any of these to 1 break the specifications,
* but it is supposed to work on most moderns systems. Use with caution.
* but it is supposed to work on most moderns systems. Use with caution.
*/
/**
* Omit the version number (";1") at the end of the ISO-9660 identifiers.
* Version numbers are usually not used.
@ -45,7 +60,7 @@ struct iso_write_opts {
unsigned int omit_version_numbers :1;
/**
* Allow ISO-9660 directory hierarchy to be deeper than 8 levels.
* Allow ISO-9660 directory hierarchy to be deeper than 8 levels.
*/
unsigned int allow_deep_paths :1;
@ -64,35 +79,74 @@ struct iso_write_opts {
/**
* ISO-9660 forces filenames to have a ".", that separates file name from
* extension. libisofs adds it if original filename doesn't has one. Set
* extension. libisofs adds it if original filename doesn't has one. Set
* this to 1 to prevent this behavior
*/
unsigned int no_force_dots :1;
/**
* Allow lowercase characters in ISO-9660 filenames. By default, only
* uppercase characters, numbers and a few other characters are allowed.
* Allow lowercase characters in ISO-9660 filenames. By default, only
* uppercase characters, numbers and a few other characters are allowed.
*/
unsigned int allow_lowercase :1;
/**
* Allow all ASCII characters to be appear on an ISO-9660 filename. Note
* that "/" and "\0" characters are never allowed, even in RR names.
*/
unsigned int allow_full_ascii :1;
/**
* Allow all characters to be part of Volume and Volset identifiers on
* the Primary Volume Descriptor. This breaks ISO-9660 contraints, but
* should work on modern systems.
*/
unsigned int relaxed_vol_atts :1;
/**
* Allow paths in the Joliet tree to have more than 240 characters.
*/
unsigned int joliet_longer_paths :1;
/**
* Write Rock Ridge info as of specification RRIP-1.10 rather than
* RRIP-1.12: signature "RRIP_1991A" rather than "IEEE_1282",
* field PX without file serial number
*/
unsigned int rrip_version_1_10 :1;
/**
* Write field PX with file serial number even with RRIP-1.10
*/
unsigned int rrip_1_10_px_ino :1;
/**
* See iso_write_opts_set_hardlinks()
*/
unsigned int hardlinks:1;
/**
* Write AAIP as extension according to SUSP 1.10 rather than SUSP 1.12.
* I.e. without announcing it by an ER field and thus without the need
* to preceed the RRIP fields by an ES and to preceed the AA field by ES.
* This saves bytes and might avoid problems with readers which dislike
* ER fields other than the ones for RRIP.
* On the other hand, SUSP 1.12 frowns on such unannounced extensions
* and prescribes ER and ES. It does this since year 1994.
*
* In effect only if above flag .aaip is set to 1.
*/
unsigned int aaip_susp_1_10 :1;
/**
* Store as ECMA-119 Directory Record timestamp the mtime of the source
* rather than the image creation time. (The ECMA-119 prescription seems
* to expect that we do have a creation timestamp with the source.
* mkisofs writes mtimes and the result seems more suitable if mounted
* without Rock Ridge support.)
*/
unsigned int dir_rec_mtime :1;
/** If files should be sorted based on their weight. */
unsigned int sort_files :1;
@ -102,7 +156,7 @@ struct iso_write_opts {
* If 0, the corresponding attribute will be kept as setted in the IsoNode.
* Unless you have changed it, it corresponds to the value on disc, so it
* is suitable for backup purposes. If set to 1, the corresponding attrib.
* will be changed by a default suitable value. Finally, if you set it to
* will be changed by a default suitable value. Finally, if you set it to
* 2, the attrib. will be changed with the value specified in the options
* below. Note that for mode attributes, only the permissions are set, the
* file type remains unchanged.
@ -133,68 +187,76 @@ struct iso_write_opts {
/**
* This flags control the type of the image to create. Libisofs support
* two kind of images: stand-alone and appendable.
*
* two kind of images: stand-alone and appendable.
*
* A stand-alone image is an image that is valid alone, and that can be
* mounted by its own. This is the kind of image you will want to create
* in most cases. A stand-alone image can be burned in an empty CD or DVD,
* or write to an .iso file for future burning or distribution.
*
*
* On the other side, an appendable image is not self contained, it refers
* to serveral files that are stored outside the image. Its usage is for
* multisession discs, where you add data in a new session, while the
* previous session data can still be accessed. In those cases, the old
* multisession discs, where you add data in a new session, while the
* previous session data can still be accessed. In those cases, the old
* data is not written again. Instead, the new image refers to it, and thus
* it's only valid when appended to the original. Note that in those cases
* the image will be written after the original, and thus you will want
* to use a ms_block greater than 0.
*
* Note that if you haven't import a previous image (by means of
* to use a ms_block greater than 0.
*
* Note that if you haven't import a previous image (by means of
* iso_image_import()), the image will always be a stand-alone image, as
* there is no previous data to refer to.
*/
unsigned int appendable : 1;
/**
* Start block of the image. It is supposed to be the lba where the first
* block of the image will be written on disc. All references inside the
* ISO image will take this into account, thus providing a mountable image.
*
* For appendable images, that are written to a new session, you should
*
* For appendable images, that are written to a new session, you should
* pass here the lba of the next writable address on disc.
*
* In stand alone images this is usually 0. However, you may want to
*
* In stand alone images this is usually 0. However, you may want to
* provide a different ms_block if you don't plan to burn the image in the
* first session on disc, such as in some CD-Extra disc whether the data
* image is written in a new session after some audio tracks.
* image is written in a new session after some audio tracks.
*/
uint32_t ms_block;
/**
* When not NULL, it should point to a buffer of at least 64KiB, where
* When not NULL, it should point to a buffer of at least 64KiB, where
* libisofs will write the contents that should be written at the beginning
* of a overwriteable media, to grow the image. The growing of an image is
* a way, used by first time in growisofs by Andy Polyakov, to allow the
* appending of new data to non-multisession media, such as DVD+RW, in the
* same way you append a new session to a multisession disc, i.e., without
* need to write again the contents of the previous image.
*
* need to write again the contents of the previous image.
*
* Note that if you want this kind of image growing, you will also need to
* set appendable to "1" and provide a valid ms_block after the previous
* image.
*
* You should initialize the buffer either with 0s, or with the contents of
* the first blocks of the image you're growing. In most cases, 0 is good
*
* You should initialize the buffer either with 0s, or with the contents of
* the first blocks of the image you're growing. In most cases, 0 is good
* enought.
*/
uint8_t *overwrite;
/**
* Size, in number of blocks, of the FIFO buffer used between the writer
* thread and the burn_source. You have to provide at least a 32 blocks
* buffer.
*/
size_t fifo_size;
/**
* This is not an option setting but a value returned after the options
* were used to compute the layout of the image.
* It tells the LBA of the first plain file data block in the image.
*/
uint32_t data_start_lba;
};
typedef struct ecma119_image Ecma119Image;
@ -217,6 +279,10 @@ struct ecma119_image
unsigned int eltorito :1;
unsigned int iso1999 :1;
unsigned int hardlinks:1; /* see iso_write_opts_set_hardlinks() */
unsigned int aaip :1; /* see iso_write_opts_set_aaip() */
/* allways write timestamps in GMT */
unsigned int always_gmt :1;
@ -228,13 +294,25 @@ struct ecma119_image
unsigned int no_force_dots :1;
unsigned int allow_lowercase :1;
unsigned int allow_full_ascii :1;
unsigned int relaxed_vol_atts : 1;
/** Allow paths on Joliet tree to be larger than 240 bytes */
unsigned int joliet_longer_paths :1;
/*
/** Write old fashioned RRIP-1.10 rather than RRIP-1.12 */
unsigned int rrip_version_1_10 :1;
/** Write field PX with file serial number even with RRIP-1.10 */
unsigned int rrip_1_10_px_ino :1;
/* Write AAIP as extension according to SUSP 1.10 rather than SUSP 1.12. */
unsigned int aaip_susp_1_10 :1;
/* Store in ECMA-119 timestamp mtime of source */
unsigned int dir_rec_mtime :1;
/*
* Mode replace. If one of these flags is set, the correspodent values are
* replaced with values below.
*/
@ -251,16 +329,22 @@ struct ecma119_image
time_t timestamp;
/**
* if sort files or not. Sorting is based of the weight of each file
* if sort files or not. Sorting is based of the weight of each file
*/
int sort_files;
#ifndef Libisofs_hardlink_matcheR
/* ts A90508 : <<< this is on its way out */
/**
* In the CD, each file must have an unique inode number. So each
* time we add a new file, this is incremented.
*/
ino_t ino;
#endif /* ! Libisofs_hardlink_matcheR */
char *input_charset;
char *output_charset;
@ -282,7 +366,7 @@ struct ecma119_image
*/
uint32_t curblock;
/*
/*
* number of dirs in ECMA-119 tree, computed together with dir position,
* and needed for path table computation in a efficient way
*/
@ -290,7 +374,7 @@ struct ecma119_image
uint32_t path_table_size;
uint32_t l_path_table_pos;
uint32_t m_path_table_pos;
/*
* Joliet related information
*/
@ -299,7 +383,7 @@ struct ecma119_image
uint32_t joliet_path_table_size;
uint32_t joliet_l_path_table_pos;
uint32_t joliet_m_path_table_pos;
/*
* ISO 9660:1999 related information
*/
@ -308,7 +392,7 @@ struct ecma119_image
uint32_t iso1999_path_table_size;
uint32_t iso1999_l_path_table_pos;
uint32_t iso1999_m_path_table_pos;
/*
* El-Torito related information
*/
@ -322,10 +406,10 @@ struct ecma119_image
* data. These padding blocks are added by libisofs to improve the handling
* of image growing. The idea is that the first blocks in the image are
* overwritten with the volume descriptors of the new image. These first
* blocks usually correspond to the volume descriptors and directory
* structure of the old image, and can be safety overwritten. However,
* with very small images they might correspond to valid data. To ensure
* this never happens, what we do is to add padding bytes, to ensure no
* blocks usually correspond to the volume descriptors and directory
* structure of the old image, and can be safety overwritten. However,
* with very small images they might correspond to valid data. To ensure
* this never happens, what we do is to add padding bytes, to ensure no
* file data is written in the first 64 KiB, that are the bytes we usually
* overwrite.
*/
@ -473,4 +557,5 @@ struct ecma119_vol_desc_terminator
uint8_t reserved BP(8, 2048);
};
#endif /*LIBISO_ECMA119_H_*/

View File

@ -1,8 +1,9 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -61,18 +62,18 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
}
} else {
if (img->max_37_char_filenames) {
isoname = iso_r_fileid(ascii_name, 36, relaxed,
isoname = iso_r_fileid(ascii_name, 36, relaxed,
img->no_force_dots ? 0 : 1);
} else if (img->iso_level == 1) {
if (relaxed) {
isoname = iso_r_fileid(ascii_name, 11, relaxed,
isoname = iso_r_fileid(ascii_name, 11, relaxed,
img->no_force_dots ? 0 : 1);
} else {
isoname = iso_1_fileid(ascii_name);
}
} else {
if (relaxed) {
isoname = iso_r_fileid(ascii_name, 30, relaxed,
isoname = iso_r_fileid(ascii_name, 30, relaxed,
img->no_force_dots ? 0 : 1);
} else {
isoname = iso_2_fileid(ascii_name);
@ -84,7 +85,7 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
*name = isoname;
return ISO_SUCCESS;
} else {
/*
/*
* only possible if mem error, as check for empty names is done
* in public tree
*/
@ -106,10 +107,38 @@ int create_ecma119_node(Ecma119Image *img, IsoNode *iso, Ecma119Node **node)
ecma->node = iso;
iso_node_ref(iso);
/* TODO #00009 : add true support for harlinks and inode numbers */
ecma->nlink = 1;
#ifndef Libisofs_hardlink_matcheR
/* ts A90503 : This is obsolete with Libisofs_hardlink_matcheR
which will later hand out image inode numbers for all. */
#ifdef Libisofs_hardlink_prooF
/* Looking only for valid ISO image inode numbers. */
{
unsigned int fs_id;
dev_t dev_id;
int ret;
ret = iso_node_get_id(iso, &fs_id, &dev_id, &(ecma->ino), 1);
if (ret < 0) {
return ret;
} else if (ret == 0) {
/* What has not got a valid ISO image inode yet, gets it now. */
ecma->ino = img_give_ino_number(img->image, 0);
}
}
#else /* Libisofs_hardlink_prooF */
/* TODO #00009 : add true support for harlinks and inode numbers */
ecma->ino = ++img->ino;
#endif /* ! Libisofs_hardlink_prooF */
#endif /* ! Libisofs_hardlink_matcheR */
*node = ecma;
return ISO_SUCCESS;
}
@ -129,7 +158,7 @@ int create_dir(Ecma119Image *img, IsoDir *iso, Ecma119Node **node)
if (children == NULL) {
return ISO_OUT_OF_MEM;
}
dir_info = calloc(1, sizeof(struct ecma119_dir_info));
if (dir_info == NULL) {
free(children);
@ -161,10 +190,13 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node)
off_t size;
size = iso_stream_get_size(iso->stream);
if (size > (off_t)0xffffffff) {
return iso_msg_submit(img->image->id, ISO_FILE_TOO_BIG, 0,
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && img->iso_level != 3) {
char *ipath = iso_tree_get_node_path(ISO_NODE(iso));
ret = iso_msg_submit(img->image->id, ISO_FILE_TOO_BIG, 0,
"File \"%s\" can't be added to image because "
"is greater than 4GB", iso->node.name);
"is greater than 4GB", ipath);
free(ipath);
return ret;
}
ret = iso_file_src_create(img, iso, &src);
@ -174,9 +206,9 @@ int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node)
ret = create_ecma119_node(img, (IsoNode*)iso, node);
if (ret < 0) {
/*
/*
* the src doesn't need to be freed, it is free together with
* the Ecma119Image
* the Ecma119Image
*/
return ret;
}
@ -203,9 +235,9 @@ int create_boot_cat(Ecma119Image *img, IsoBoot *iso, Ecma119Node **node)
ret = create_ecma119_node(img, (IsoNode*)iso, node);
if (ret < 0) {
/*
/*
* the src doesn't need to be freed, it is free together with
* the Ecma119Image
* the Ecma119Image
*/
return ret;
}
@ -267,10 +299,10 @@ void ecma119_node_free(Ecma119Node *node)
}
/**
*
* @return
*
* @return
* 1 success, 0 node ignored, < 0 error
*
*
*/
static
int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
@ -296,15 +328,21 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
max_path = pathlen + 1 + (iso_name ? strlen(iso_name) : 0);
if (!image->rockridge) {
if ((iso->type == LIBISO_DIR && depth > 8) && !image->allow_deep_paths) {
free(iso_name);
char *ipath = iso_tree_get_node_path(iso);
return iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
"File \"%s\" can't be added, because directory depth "
"is greater than 8.", iso->name);
} else if (max_path > 255 && !image->allow_longer_paths) {
"is greater than 8.", ipath);
free(iso_name);
return iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
free(ipath);
return ret;
} else if (max_path > 255 && !image->allow_longer_paths) {
char *ipath = iso_tree_get_node_path(iso);
ret = iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
"File \"%s\" can't be added, because path length "
"is greater than 255 characters", iso->name);
"is greater than 255 characters", ipath);
free(iso_name);
free(ipath);
return ret;
}
}
@ -317,19 +355,23 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
ret = create_symlink(image, (IsoSymlink*)iso, &node);
} else {
/* symlinks are only supported when RR is enabled */
char *ipath = iso_tree_get_node_path(iso);
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
"File \"%s\" ignored. Symlinks need RockRidge extensions.",
iso->name);
"File \"%s\" ignored. Symlinks need RockRidge extensions.",
ipath);
free(ipath);
}
break;
case LIBISO_SPECIAL:
if (image->rockridge) {
ret = create_special(image, (IsoSpecial*)iso, &node);
} else {
/* symlinks are only supported when RR is enabled */
/* special files are only supported when RR is enabled */
char *ipath = iso_tree_get_node_path(iso);
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
"File \"%s\" ignored. Special files need RockRidge extensions.",
iso->name);
"File \"%s\" ignored. Special files need RockRidge extensions.",
ipath);
free(ipath);
}
break;
case LIBISO_BOOT:
@ -338,8 +380,7 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
} else {
/* log and ignore */
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
"El-Torito catalog found on a image without El-Torito.",
iso->name);
"El-Torito catalog found on a image without El-Torito.");
}
break;
case LIBISO_DIR:
@ -430,9 +471,9 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
nchildren = dir->info.dir->nchildren;
children = dir->info.dir->children;
/* a hash table will temporary hold the names, for fast searching */
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
(compare_function_t)strcmp, &table);
if (ret < 0) {
return ret;
@ -463,7 +504,7 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
}
/*
* A max of 7 characters is good enought, it allows handling up to
* A max of 7 characters is good enought, it allows handling up to
* 9,999,999 files with same name. We can increment this to
* max_name_len, but the int_pow() function must then be modified
* to return a bigger integer.
@ -480,8 +521,8 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
dot = strrchr(full_name, '.');
if (dot != NULL && children[i]->type != ECMA119_DIR) {
/*
* File (not dir) with extension
/*
* File (not dir) with extension
* Note that we don't need to check for placeholders, as
* tree reparent happens later, so no placeholders can be
* here at this time.
@ -491,26 +532,26 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
name = full_name;
ext = dot + 1;
/*
/*
* For iso level 1 we force ext len to be 3, as name
* can't grow on the extension space
* can't grow on the extension space
*/
extlen = (max_file_len == 12) ? 3 : strlen(ext);
max = max_file_len - extlen - 1 - digits;
if (max <= 0) {
/* this can happen if extension is too long */
if (extlen + max > 3) {
/*
/*
* reduce extension len, to give name an extra char
* note that max is negative or 0
* note that max is negative or 0
*/
extlen = extlen + max - 1;
ext[extlen] = '\0';
max = max_file_len - extlen - 1 - digits;
} else {
/*
/*
* error, we don't support extensions < 3
* This can't happen with current limit of digits.
* This can't happen with current limit of digits.
*/
ret = ISO_ERROR;
goto mangle_cleanup;
@ -572,7 +613,7 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
children[k]->iso_name = new;
iso_htable_add(table, new, new);
/*
/*
* if we change a name we need to sort again children
* at the end
*/
@ -603,7 +644,7 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
}
ret = ISO_SUCCESS;
mangle_cleanup : ;
iso_htable_destroy(table, NULL);
return ret;
@ -658,7 +699,7 @@ int mangle_tree(Ecma119Image *img, int recurse)
/**
* Create a new ECMA-119 node representing a placeholder for a relocated
* dir.
*
*
* See IEEE P1282, section 4.1.5 for details
*/
static
@ -672,10 +713,10 @@ int create_placeholder(Ecma119Node *parent, Ecma119Node *real,
return ISO_OUT_OF_MEM;
}
/*
/*
* TODO
* If real is a dir, while placeholder is a file, ISO name restricctions
* are different, what to do?
* If real is a dir, while placeholder is a file, ISO name restricctions
* are different, what to do?
*/
ret->iso_name = strdup(real->iso_name);
if (ret->iso_name == NULL) {
@ -708,10 +749,10 @@ size_t max_child_name_len(Ecma119Node *dir)
}
/**
* Relocates a directory, as specified in Rock Ridge Specification
* Relocates a directory, as specified in Rock Ridge Specification
* (see IEEE P1282, section 4.1.5). This is needed when the number of levels
* on a directory hierarchy exceeds 8, or the length of a path is higher
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
*/
static
int reparent(Ecma119Node *child, Ecma119Node *parent)
@ -743,7 +784,7 @@ int reparent(Ecma119Node *child, Ecma119Node *parent)
/* add the child to its new parent */
child->parent = parent;
parent->info.dir->nchildren++;
parent->info.dir->children = realloc(parent->info.dir->children,
parent->info.dir->children = realloc(parent->info.dir->children,
sizeof(void*) * parent->info.dir->nchildren);
parent->info.dir->children[parent->info.dir->nchildren - 1] = child;
return ISO_SUCCESS;
@ -754,7 +795,7 @@ int reparent(Ecma119Node *child, Ecma119Node *parent)
* - the depth is at most 8
* - each path length is at most 255 characters
* This restriction is imposed by ECMA-119 specification (ECMA-119, 6.8.2.1).
*
*
* @param dir
* Dir we are currently processing
* @param level
@ -778,9 +819,9 @@ int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen)
return ret;
}
/*
/*
* we are appended to the root's children now, so there is no
* need to recurse (the root will hit us again)
* need to recurse (the root will hit us again)
*/
} else {
size_t i;
@ -799,6 +840,174 @@ int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen)
return ISO_SUCCESS;
}
/*
* @param flag
* bit0= recursion
* bit1= count nodes rather than fill them into *nodes
* @return
* <0 error
* bit0= saw ino == 0
* bit1= saw ino != 0
*/
static
int make_node_array(Ecma119Image *img, Ecma119Node *dir,
Ecma119Node **nodes, size_t nodes_size, size_t *node_count,
int flag)
{
int ret, result = 0;
size_t i;
Ecma119Node *child;
if (!(flag & 1)) {
*node_count = 0;
if (!(flag & 2)) {
/* Register the tree root node */
if (*node_count >= nodes_size) {
iso_msg_submit(img->image->id, ISO_ASSERT_FAILURE, 0,
"Programming error: Overflow of hardlink sort array");
return ISO_ASSERT_FAILURE;
}
nodes[*node_count] = dir;
}
result|= (dir->ino == 0 ? 1 : 2);
(*node_count)++;
}
for (i = 0; i < dir->info.dir->nchildren; i++) {
child = dir->info.dir->children[i];
if (!(flag & 2)) {
if (*node_count >= nodes_size) {
iso_msg_submit(img->image->id, ISO_ASSERT_FAILURE, 0,
"Programming error: Overflow of hardlink sort array");
return ISO_ASSERT_FAILURE;
}
nodes[*node_count] = child;
}
result|= (child->ino == 0 ? 1 : 2);
(*node_count)++;
if (child->type == ECMA119_DIR) {
ret = make_node_array(img, child,
nodes, nodes_size, node_count, flag | 1);
if (ret < 0)
return ret;
}
}
return result;
}
/*
* @param flag
* bit0= compare stat properties and attributes
* bit1= treat all nodes with image ino == 0 as unique
*/
static
int ecma119_node_cmp_flag(const void *v1, const void *v2, int flag)
{
int ret;
Ecma119Node *n1, *n2;
n1 = *((Ecma119Node **) v1);
n2 = *((Ecma119Node **) v2);
if (n1 == n2)
return 0;
ret = iso_node_cmp_flag(n1->node, n2->node, flag & (1 | 2));
return ret;
}
static
int ecma119_node_cmp_hard(const void *v1, const void *v2)
{
return ecma119_node_cmp_flag(v1, v2, 1);
}
static
int ecma119_node_cmp_nohard(const void *v1, const void *v2)
{
return ecma119_node_cmp_flag(v1, v2, 1 | 2);
}
static
int family_set_ino(Ecma119Image *img, Ecma119Node **nodes, size_t family_start,
size_t next_family, ino_t img_ino, ino_t prev_ino, int flag)
{
size_t i;
if (img_ino != 0) {
/* Check whether this is the same img_ino as in the previous
family (e.g. by property divergence of imported hardlink).
*/
if (img_ino == prev_ino)
img_ino = 0;
}
if (img_ino == 0) {
img_ino = img_give_ino_number(img->image, 0);
}
for (i = family_start; i < next_family; i++) {
nodes[i]->ino = img_ino;
nodes[i]->nlink = next_family - family_start;
}
return 1;
}
static
int match_hardlinks(Ecma119Image *img, Ecma119Node *dir, int flag)
{
int ret;
size_t nodes_size = 0, node_count = 0, i, family_start;
Ecma119Node **nodes = NULL;
unsigned int fs_id;
dev_t dev_id;
ino_t img_ino = 0, prev_ino = 0;
ret = make_node_array(img, dir, nodes, nodes_size, &node_count, 2);
if (ret < 0)
return ret;
nodes_size = node_count;
nodes = (Ecma119Node **) calloc(sizeof(Ecma119Node *), nodes_size);
if (nodes == NULL)
return ISO_OUT_OF_MEM;
ret = make_node_array(img, dir, nodes, nodes_size, &node_count, 0);
if (ret < 0)
goto ex;
/* Sort according to id tuples, IsoFileSrc identity, properties, xattr. */
if (img->hardlinks)
qsort(nodes, node_count, sizeof(Ecma119Node *), ecma119_node_cmp_hard);
else
qsort(nodes, node_count, sizeof(Ecma119Node *),
ecma119_node_cmp_nohard);
/* Hand out image inode numbers to all Ecma119Node.ino == 0 .
Same sorting rank gets same inode number.
Split those image inode number families where the sort criterion
differs.
*/
iso_node_get_id(nodes[0]->node, &fs_id, &dev_id, &img_ino, 1);
family_start = 0;
for (i = 1; i < node_count; i++) {
if (ecma119_node_cmp_hard(nodes + (i - 1), nodes + i) == 0) {
/* Still in same ino family */
if (img_ino == 0) { /* Just in case any member knows its img_ino */
iso_node_get_id(nodes[0]->node, &fs_id, &dev_id, &img_ino, 1);
}
continue;
}
family_set_ino(img, nodes, family_start, i, img_ino, prev_ino, 0);
prev_ino = img_ino;
iso_node_get_id(nodes[i]->node, &fs_id, &dev_id, &img_ino, 1);
family_start = i;
}
family_set_ino(img, nodes, family_start, i, img_ino, prev_ino, 0);
ret = ISO_SUCCESS;
ex:;
if (nodes != NULL)
free((char *) nodes);
return ret;
}
int ecma119_tree_create(Ecma119Image *img)
{
int ret;
@ -814,6 +1023,16 @@ int ecma119_tree_create(Ecma119Image *img)
}
img->root = root;
#ifdef Libisofs_hardlink_matcheR
iso_msg_debug(img->image->id, "Matching hardlinks...");
ret = match_hardlinks(img, img->root, 0);
if (ret < 0) {
return ret;
}
#endif /* ! Libisofs_hardlink_matcheR */
iso_msg_debug(img->image->id, "Sorting the low level tree...");
sort_tree(root);
@ -831,7 +1050,7 @@ int ecma119_tree_create(Ecma119Image *img)
return ret;
}
/*
/*
* and we need to remangle the root directory, as the function
* above could insert new directories into the root.
* Note that recurse = 0, as we don't need to recurse.

View File

@ -62,8 +62,10 @@ struct ecma119_node
IsoNode *node; /*< reference to the iso node */
/* TODO #00009 : add true support for harlinks and inode numbers */
/* >>> ts A90501 : Shouldn't this be uint32_t
as this is what PX will take ? */
ino_t ino;
nlink_t nlink;
/**< file, symlink, special, directory or placeholder */

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -26,7 +26,7 @@ struct boot_info_table {
uint8_t bi_file BP(5, 8); /* LBA of boot file */
uint8_t bi_length BP(9, 12); /* Length of boot file */
uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
uint8_t bi_reserved BP(17, 56); /* Reserved */
uint8_t bi_reserved BP(17, 56); /* Reserved */
};
/**
@ -60,19 +60,19 @@ struct hard_disc_mbr {
*/
void el_torito_set_load_seg(ElToritoBootImage *bootimg, short segment)
{
if (bootimg->type != ELTORITO_NO_EMUL)
if (bootimg->type != 0)
return;
bootimg->load_seg = segment;
}
/**
* Sets the number of sectors (512b) to be load at load segment during
* the initial boot procedure. This is only for no emulation boot images,
* the initial boot procedure. This is only for no emulation boot images,
* and is a NOP for other image types.
*/
void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors)
{
if (bootimg->type != ELTORITO_NO_EMUL)
if (bootimg->type != 0)
return;
bootimg->load_size = sectors;
}
@ -93,7 +93,61 @@ void el_torito_set_no_bootable(ElToritoBootImage *bootimg)
*/
void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg)
{
bootimg->isolinux = 1;
bootimg->isolinux_options |= 0x01;
}
/**
* Specifies options for IsoLinux boot images. This should only be used with
* isolinux boot images.
*
* @param options
* bitmask style flag. The following values are defined:
*
* bit 0 -> 1 to path the image, 0 to not
* Patching the image involves the writting of a 56 bytes
* boot information table at offset 8 of the boot image file.
* The original boot image file won't be modified. This is needed
* to allow isolinux images to be bootable.
* bit 1 -> 1 to generate an hybrid image, 0 to not
* An hybrid image is a boot image that boots from either CD/DVD
* media or from USB sticks. For that, you should use an isolinux
* image that supports hybrid mode. Recent images support this.
* @return
* 1 if success, < 0 on error
* @since 0.6.12
*/
int el_torito_set_isolinux_options(ElToritoBootImage *bootimg, int options, int flag)
{
bootimg->isolinux_options = (options & 0x03);
return ISO_SUCCESS;
}
/* TODO getter for boot image properties should be exposed
* useful when reading discs */
int el_torito_get_boot_media_type(const ElToritoBootImage *bootimg)
{
if (bootimg) {
switch (bootimg->type) {
case 1:
case 2:
case 3:
return ELTORITO_FLOPPY_EMUL;
break;
case 4:
return ELTORITO_HARD_DISC_EMUL;
break;
case 0:
return ELTORITO_NO_EMUL;
break;
default:
/* should never happen */
return ISO_ASSERT_FAILURE;
break;
}
} else {
return ISO_WRONG_ARG_VALUE;
}
}
static
@ -109,7 +163,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
if (boot) {
*boot = NULL;
}
/* check if the name is valid */
if (!iso_node_is_valid_name(name)) {
return ISO_WRONG_ARG_VALUE;
@ -162,7 +216,7 @@ int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
}
static
static
int create_image(IsoImage *image, const char *image_path,
enum eltorito_boot_media_type type,
struct el_torito_boot_image **bootimg)
@ -182,18 +236,18 @@ int create_image(IsoImage *image, const char *image_path,
if (ret == 0) {
return ISO_NODE_DOESNT_EXIST;
}
if (imgfile->type != LIBISO_FILE) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
stream = ((IsoFile*)imgfile)->stream;
/* we need to read the image at least two times */
if (!iso_stream_is_repeatable(stream)) {
return ISO_BOOT_IMAGE_NOT_VALID;
}
switch (type) {
case ELTORITO_FLOPPY_EMUL:
switch (iso_stream_get_size(stream)) {
@ -211,9 +265,9 @@ int create_image(IsoImage *image, const char *image_path,
"Invalid image size %d Kb. Must be one of 1.2, 1.44"
"or 2.88 Mb", iso_stream_get_size(stream) / 1024);
return ISO_BOOT_IMAGE_NOT_VALID;
break;
break;
}
/* it seems that for floppy emulation we need to load
/* it seems that for floppy emulation we need to load
* a single sector (512b) */
load_sectors = 1;
break;
@ -222,7 +276,7 @@ int create_image(IsoImage *image, const char *image_path,
size_t i;
struct hard_disc_mbr mbr;
int used_partition;
/* read the MBR on disc and get the type of the partition */
ret = iso_stream_open(stream);
if (ret < 0) {
@ -237,14 +291,14 @@ int create_image(IsoImage *image, const char *image_path,
"Can't read MBR from image file.");
return ret < 0 ? ret : ISO_FILE_READ_ERROR;
}
/* check valid MBR signature */
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Invalid MBR. Wrong signature.");
return ISO_BOOT_IMAGE_NOT_VALID;
}
/* ensure single partition */
used_partition = -1;
for (i = 0; i < 4; ++i) {
@ -252,7 +306,7 @@ int create_image(IsoImage *image, const char *image_path,
/* it's an used partition */
if (used_partition != -1) {
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
"Invalid MBR. At least 2 partitions: %d and "
"Invalid MBR. At least 2 partitions: %d and "
"%d, are being used\n", used_partition, i);
return ISO_BOOT_IMAGE_NOT_VALID;
} else
@ -262,15 +316,15 @@ int create_image(IsoImage *image, const char *image_path,
partition_type = mbr.partition[used_partition].type;
}
boot_media_type = 4;
/* only load the MBR */
load_sectors = 1;
break;
case ELTORITO_NO_EMUL:
boot_media_type = 0;
break;
break;
}
boot = calloc(1, sizeof(struct el_torito_boot_image));
if (boot == NULL) {
return ISO_OUT_OF_MEM;
@ -281,11 +335,11 @@ int create_image(IsoImage *image, const char *image_path,
boot->type = boot_media_type;
boot->load_size = load_sectors;
boot->partition_type = partition_type;
if (bootimg) {
*bootimg = boot;
}
return ISO_SUCCESS;
}
@ -298,14 +352,14 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
struct el_torito_boot_catalog *catalog;
ElToritoBootImage *boot_image= NULL;
IsoBoot *cat_node= NULL;
if (image == NULL || image_path == NULL || catalog_path == NULL) {
return ISO_NULL_POINTER;
}
if (image->bootcat != NULL) {
return ISO_IMAGE_ALREADY_BOOTABLE;
}
/* create the node for the catalog */
{
IsoDir *parent;
@ -314,8 +368,8 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
if (catdir == NULL) {
return ISO_OUT_OF_MEM;
}
/* get both the dir and the name */
/* get both the dir and the name */
catname = strrchr(catdir, '/');
if (catname == NULL) {
free(catdir);
@ -345,13 +399,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
return ret;
}
}
/* create the boot image */
ret = create_image(image, image_path, type, &boot_image);
if (ret < 0) {
goto boot_image_cleanup;
}
/* creates the catalog with the given image */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
if (catalog == NULL) {
@ -362,13 +416,13 @@ int iso_image_set_boot_image(IsoImage *image, const char *image_path,
catalog->node = cat_node;
iso_node_ref((IsoNode*)cat_node);
image->bootcat = catalog;
if (boot) {
*boot = boot_image;
}
return ISO_SUCCESS;
boot_image_cleanup:;
if (cat_node) {
iso_node_take((IsoNode*)cat_node);
@ -383,32 +437,32 @@ boot_image_cleanup:;
/**
* Get El-Torito boot image of an ISO image, if any.
*
*
* This can be useful, for example, to check if a volume read from a previous
* session or an existing image is bootable. It can also be useful to get
* the image and catalog tree nodes. An application would want those, for
* the image and catalog tree nodes. An application would want those, for
* example, to prevent the user removing it.
*
*
* Both nodes are owned by libisofs and should not be freed. You can get your
* own ref with iso_node_ref(). You can can also check if the node is already
* on the tree by getting its parent (note that when reading El-Torito info
* from a previous image, the nodes might not be on the tree even if you haven't
* removed them). Remember that you'll need to get a new ref
* (with iso_node_ref()) before inserting them again to the tree, and probably
* own ref with iso_node_ref(). You can can also check if the node is already
* on the tree by getting its parent (note that when reading El-Torito info
* from a previous image, the nodes might not be on the tree even if you haven't
* removed them). Remember that you'll need to get a new ref
* (with iso_node_ref()) before inserting them again to the tree, and probably
* you will also need to set the name or permissions.
*
*
* @param image
* The image from which to get the boot image.
* @param boot
* If not NULL, it will be filled with a pointer to the boot image, if
* any. That object is owned by the IsoImage and should not be freed by
* If not NULL, it will be filled with a pointer to the boot image, if
* any. That object is owned by the IsoImage and should not be freed by
* the user, nor dereferenced once the last reference to the IsoImage was
* disposed via iso_image_unref().
* @param imgnode
* @param imgnode
* When not NULL, it will be filled with the image tree node. No extra ref
* is added, you can use iso_node_ref() to get one if you need it.
* @param catnode
* When not NULL, it will be filled with the catnode tree node. No extra
* @param catnode
* When not NULL, it will be filled with the catnode tree node. No extra
* ref is added, you can use iso_node_ref() to get one if you need it.
* @return
* 1 on success, 0 is the image is not bootable (i.e., it has no El-Torito
@ -423,7 +477,7 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
if (image->bootcat == NULL) {
return 0;
}
/* ok, image is bootable */
if (boot) {
*boot = image->bootcat->image;
@ -438,8 +492,8 @@ int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
}
/**
* Removes the El-Torito bootable image.
*
* Removes the El-Torito bootable image.
*
* The IsoBoot node that acts as placeholder for the catalog is also removed
* for the image tree, if there.
* If the image is not bootable (don't have el-torito boot image) this function
@ -449,13 +503,13 @@ void iso_image_remove_boot_image(IsoImage *image)
{
if (image == NULL || image->bootcat == NULL)
return;
/*
* remove catalog node from its parent
* (the reference will be disposed next)
/*
* remove catalog node from its parent
* (the reference will be disposed next)
*/
iso_node_take((IsoNode*)image->bootcat->node);
/* free boot catalog and image, including references to nodes */
el_torito_boot_catalog_free(image->bootcat);
image->bootcat = NULL;
@ -464,11 +518,11 @@ void iso_image_remove_boot_image(IsoImage *image)
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
{
struct el_torito_boot_image *image;
if (cat == NULL) {
return;
}
image = cat->image;
iso_node_unref((IsoNode*)image->image);
free(image);
@ -486,19 +540,19 @@ struct catalog_stream
int offset; /* -1 if stream is not openned */
};
static void
static void
write_validation_entry(uint8_t *buf)
{
size_t i;
int checksum;
struct el_torito_validation_entry *ve =
struct el_torito_validation_entry *ve =
(struct el_torito_validation_entry*)buf;
ve->header_id[0] = 1;
ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */
ve->key_byte1[0] = 0x55;
ve->key_byte2[0] = 0xAA;
/* calculate the checksum, to ensure sum of all words is 0 */
checksum = 0;
for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
@ -515,9 +569,9 @@ static void
write_section_entry(uint8_t *buf, Ecma119Image *t)
{
struct el_torito_boot_image *img;
struct el_torito_section_entry *se =
struct el_torito_section_entry *se =
(struct el_torito_section_entry*)buf;
img = t->catalog->image;
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
@ -525,7 +579,7 @@ write_section_entry(uint8_t *buf, Ecma119Image *t)
iso_lsb(se->load_seg, img->load_seg, 2);
se->system_type[0] = img->partition_type;
iso_lsb(se->sec_count, img->load_size, 2);
iso_lsb(se->block, t->bootimg->block, 4);
iso_lsb(se->block, t->bootimg->sections[0].block, 4);
}
static
@ -536,13 +590,13 @@ int catalog_open(IsoStream *stream)
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->offset != -1) {
return ISO_FILE_ALREADY_OPENNED;
return ISO_FILE_ALREADY_OPENED;
}
memset(data->buffer, 0, BLOCK_SIZE);
/* fill the buffer with the catalog contents */
write_validation_entry(data->buffer);
@ -561,9 +615,9 @@ int catalog_close(IsoStream *stream)
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
data->offset = -1;
return ISO_SUCCESS;
@ -587,11 +641,11 @@ int catalog_read(IsoStream *stream, void *buf, size_t count)
return ISO_WRONG_ARG_VALUE;
}
data = stream->data;
if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
len = MIN(count, BLOCK_SIZE - data->offset);
memcpy(buf, data->buffer + data->offset, len);
return len;
@ -606,7 +660,7 @@ int catalog_is_repeatable(IsoStream *stream)
/**
* fs_id will be the id reserved for El-Torito
* dev_id will be 0 for catalog, 1 for boot image (if needed)
* we leave ino_id for future use when we support multiple boot images
* we leave ino_id for future use when we support multiple boot images
*/
static
void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
@ -617,12 +671,6 @@ void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
*ino_id = 0;
}
static
char *catalog_get_name(IsoStream *stream)
{
return strdup("El-Torito Boot Catalog");
}
static
void catalog_free(IsoStream *stream)
{
@ -630,18 +678,19 @@ void catalog_free(IsoStream *stream)
}
IsoStreamIface catalog_stream_class = {
0,
"boot",
catalog_open,
catalog_close,
catalog_get_size,
catalog_read,
catalog_is_repeatable,
catalog_get_id,
catalog_get_name,
catalog_free
};
/**
* Create an IsoStream for writing El-Torito catalog for a given target.
* Create an IsoStream for writing El-Torito catalog for a given target.
*/
static
int catalog_stream_new(Ecma119Image *target, IsoStream **stream)
@ -680,17 +729,17 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
int ret;
IsoFileSrc *file;
IsoStream *stream;
if (target == NULL || src == NULL || target->catalog == NULL) {
return ISO_OUT_OF_MEM;
}
if (target->cat != NULL) {
/* catalog file src already created */
*src = target->cat;
return ISO_SUCCESS;
}
file = malloc(sizeof(IsoFileSrc));
if (file == NULL) {
return ISO_OUT_OF_MEM;
@ -701,10 +750,11 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
free(file);
return ret;
}
/* fill fields */
file->prev_img = 0; /* TODO allow copy of old img catalog???? */
file->block = 0; /* to be filled later */
file->nsections = 1;
file->sections = calloc(1, sizeof(struct iso_file_section));
file->sort_weight = 1000; /* slightly high */
file->stream = stream;
@ -720,10 +770,104 @@ int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
/******************* EL-TORITO WRITER *******************************/
/**
* Patch an isolinux boot image.
*
* @return
* 1 on success, 0 error (but continue), < 0 error
*/
static
int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
{
struct boot_info_table *info;
uint32_t checksum;
size_t offset;
if (imgsize < 64) {
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Isolinux image too small. We won't patch it.");
}
/* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */
checksum = 0;
offset = (size_t) 64;
while (offset <= imgsize - 4) {
checksum += iso_read_lsb(buf + offset, 4);
offset += 4;
}
if (offset != imgsize) {
/*
* file length not multiple of 4
* empty space in isofs is padded with zero;
* assume same for last dword
*/
checksum += iso_read_lsb(buf + offset, imgsize - offset);
}
/* patch boot info table */
info = (struct boot_info_table*)(buf + 8);
/*memset(info, 0, sizeof(struct boot_info_table));*/
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
iso_lsb(info->bi_file, t->bootimg->sections[0].block, 4);
iso_lsb(info->bi_length, imgsize, 4);
iso_lsb(info->bi_csum, checksum, 4);
return ISO_SUCCESS;
}
static
int eltorito_writer_compute_data_blocks(IsoImageWriter *writer)
{
/* nothing to do, the files are written by the file writer */
/*
* We have nothing to write, but if we need to patch an isolinux image,
* this is a good place to do so.
*/
Ecma119Image *t;
int ret;
if (writer == NULL) {
return ISO_NULL_POINTER;
}
t = writer->target;
if (t->catalog->image->isolinux_options & 0x01) {
/* we need to patch the image */
size_t size;
uint8_t *buf;
IsoStream *new = NULL;
IsoStream *original = t->bootimg->stream;
size = (size_t) iso_stream_get_size(original);
buf = malloc(size);
if (buf == NULL) {
return ISO_OUT_OF_MEM;
}
ret = iso_stream_open(original);
if (ret < 0) {
return ret;
}
ret = iso_stream_read(original, buf, size);
iso_stream_close(original);
if (ret != size) {
return (ret < 0) ? ret : ISO_FILE_READ_ERROR;
}
/* ok, patch the read buffer */
ret = patch_boot_image(buf, t, size);
if (ret < 0) {
return ret;
}
/* replace the original stream with a memory stream that reads from
* the patched buffer */
ret = iso_memory_stream_new(buf, size, &new);
if (ret < 0) {
return ret;
}
t->bootimg->stream = new;
iso_stream_unref(original);
}
return ISO_SUCCESS;
}
@ -751,106 +895,15 @@ int eltorito_writer_write_vol_desc(IsoImageWriter *writer)
memcpy(vol.std_identifier, "CD001", 5);
vol.vol_desc_version[0] = 1;
memcpy(vol.boot_sys_id, "EL TORITO SPECIFICATION", 23);
iso_lsb(vol.boot_catalog, t->cat->block, 4);
return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
}
iso_lsb(vol.boot_catalog, t->cat->sections[0].block, 4);
/**
* Patch an isolinux boot image.
*
* @return
* 1 on success, 0 error (but continue), < 0 error
*/
static
int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
{
struct boot_info_table *info;
uint32_t checksum;
size_t offset;
if (imgsize < 64) {
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Isolinux image too small. We won't patch it.");
}
/* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */
checksum = 0;
offset = (size_t) 64;
while (offset <= imgsize - 4) {
checksum += iso_read_lsb(buf + offset, 4);
offset += 4;
}
if (offset != imgsize) {
/* file length not multiple of 4 */
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
"Unexpected isolinux image length. Patch might not work.");
}
/* patch boot info table */
info = (struct boot_info_table*)(buf + 8);
/*memset(info, 0, sizeof(struct boot_info_table));*/
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
iso_lsb(info->bi_file, t->bootimg->block, 4);
iso_lsb(info->bi_length, imgsize, 4);
iso_lsb(info->bi_csum, checksum, 4);
return ISO_SUCCESS;
return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
}
static
int eltorito_writer_write_data(IsoImageWriter *writer)
{
/*
* We have nothing to write, but if we need to patch an isolinux image,
* this is a good place to do so.
*/
Ecma119Image *t;
int ret;
if (writer == NULL) {
return ISO_NULL_POINTER;
}
t = writer->target;
if (t->catalog->image->isolinux) {
/* we need to patch the image */
size_t size;
uint8_t *buf;
IsoStream *new = NULL;
IsoStream *original = t->bootimg->stream;
size = (size_t) iso_stream_get_size(original);
buf = malloc(size);
if (buf == NULL) {
return ISO_OUT_OF_MEM;
}
ret = iso_stream_open(original);
if (ret < 0) {
return ret;
}
ret = iso_stream_read(original, buf, size);
iso_stream_close(original);
if (ret != size) {
return (ret < 0) ? ret : ISO_FILE_READ_ERROR;
}
/* ok, patch the read buffer */
ret = patch_boot_image(buf, t, size);
if (ret < 0) {
return ret;
}
/* replace the original stream with a memory stream that reads from
* the patched buffer */
ret = iso_memory_stream_new(buf, size, &new);
if (ret < 0) {
return ret;
}
t->bootimg->stream = new;
iso_stream_unref(original);
}
/* nothing to do, the files are written by the file writer */
return ISO_SUCCESS;
}
@ -883,7 +936,7 @@ int eltorito_writer_create(Ecma119Image *target)
/* add this writer to image */
target->writers[target->nwriters++] = writer;
/*
/*
* get catalog and image file sources.
* Note that the catalog may be already added, when creating the low
* level ECMA-119 tree.
@ -900,9 +953,9 @@ int eltorito_writer_create(Ecma119Image *target)
return ret;
}
target->bootimg = src;
/* if we have selected to patch the image, it needs to be copied always */
if (target->catalog->image->isolinux) {
if (target->catalog->image->isolinux_options & 0x01) {
src->prev_img = 0;
}

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -35,7 +35,12 @@ struct el_torito_boot_image {
IsoFile *image;
unsigned int bootable:1; /**< If the entry is bootable. */
unsigned int isolinux:1; /**< If the image will be patched */
/**
* isolinux options
* bit 0 -> whether to patch image
* bit 1 -> whether to create isolinux image
*/
unsigned int isolinux_options:2;
unsigned char type; /**< The type of image */
unsigned char partition_type; /**< type of partition for HD-emul images */
short load_seg; /**< Load segment for the initial boot image. */

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -12,38 +12,28 @@
#include "writer.h"
#include "messages.h"
#include "image.h"
#include "stream.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int iso_file_src_cmp(const void *n1, const void *n2)
{
int ret;
const IsoFileSrc *f1, *f2;
unsigned int fs_id1, fs_id2;
dev_t dev_id1, dev_id2;
ino_t ino_id1, ino_id2;
if (n1 == n2) {
return 0; /* Normally just a shortcut.
But important if Libisofs_file_src_cmp_non_zerO */
}
f1 = (const IsoFileSrc *)n1;
f2 = (const IsoFileSrc *)n2;
iso_stream_get_id(f1->stream, &fs_id1, &dev_id1, &ino_id1);
iso_stream_get_id(f2->stream, &fs_id2, &dev_id2, &ino_id2);
if (fs_id1 < fs_id2) {
return -1;
} else if (fs_id1 > fs_id2) {
return 1;
} else {
/* files belong to the same fs */
if (dev_id1 > dev_id2) {
return -1;
} else if (dev_id1 < dev_id2) {
return 1;
} else {
/* files belong to same device in same fs */
return (ino_id1 < ino_id2) ? -1 : (ino_id1 > ino_id2) ? 1 : 0;
}
}
ret = iso_stream_cmp_ino(f1->stream, f2->stream, 0);
return ret;
}
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
@ -60,20 +50,45 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
iso_stream_get_id(file->stream, &fs_id, &dev_id, &ino_id);
fsrc = malloc(sizeof(IsoFileSrc));
fsrc = calloc(1, sizeof(IsoFileSrc));
if (fsrc == NULL) {
return ISO_OUT_OF_MEM;
}
/* fill key and other atts */
fsrc->prev_img = file->msblock ? 1 : 0;
fsrc->block = file->msblock;
fsrc->prev_img = file->from_old_session;
if (file->from_old_session && img->appendable) {
/*
* On multisession discs we keep file sections from old image.
*/
int ret = iso_file_get_old_image_sections(file, &(fsrc->nsections),
&(fsrc->sections), 0);
if (ret < 0) {
free(fsrc);
return ISO_OUT_OF_MEM;
}
} else {
/*
* For new files, or for image copy, we compute our own file sections.
* Block and size of each section will be filled later.
*/
off_t section_size = iso_stream_get_size(file->stream);
if (section_size > (off_t) MAX_ISO_FILE_SECTION_SIZE) {
fsrc->nsections = DIV_UP(section_size - (off_t) MAX_ISO_FILE_SECTION_SIZE,
(off_t)ISO_EXTENT_SIZE) + 1;
} else {
fsrc->nsections = 1;
}
fsrc->sections = calloc(fsrc->nsections, sizeof(struct iso_file_section));
}
fsrc->sort_weight = file->sort_weight;
fsrc->stream = file->stream;
/* insert the filesrc in the tree */
ret = iso_rbtree_insert(img->files, fsrc, (void**)src);
if (ret <= 0) {
free(fsrc->sections);
free(fsrc);
return ret;
}
@ -83,12 +98,12 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
/**
* Add a given IsoFileSrc to the given image target.
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
* being written several times to image. If you call again this function
* with a node that refers to the same source file, the previously
* created one will be returned.
*
*
* @param img
* The image where this file is to be written
* @param new
@ -96,7 +111,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
* @param src
* Will be filled with a pointer to the IsoFileSrc really present in
* the tree. It could be different than new if the same file already
* exists in the tree.
* exists in the tree.
* @return
* 1 on success, 0 if file already exists on tree, < 0 error
*/
@ -107,7 +122,7 @@ int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
if (img == NULL || new == NULL || src == NULL) {
return ISO_NULL_POINTER;
}
/* insert the filesrc in the tree */
ret = iso_rbtree_insert(img->files, new, (void**)src);
return ret;
@ -116,6 +131,7 @@ int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
void iso_file_src_free(void *node)
{
iso_stream_unref(((IsoFileSrc*)node)->stream);
free(((IsoFileSrc*)node)->sections);
free(node);
}
@ -159,7 +175,7 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
} else {
inc_item = NULL;
}
/* store the filesrcs in a array */
filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files, inc_item, &size);
if (filelist == NULL) {
@ -173,8 +189,23 @@ int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
/* fill block value */
for (i = 0; i < size; ++i) {
int extent = 0;
IsoFileSrc *file = filelist[i];
file->block = t->curblock;
off_t section_size = iso_stream_get_size(file->stream);
for (extent = 0; extent < file->nsections - 1; ++extent) {
file->sections[extent].block = t->curblock + extent *
(ISO_EXTENT_SIZE / BLOCK_SIZE);
file->sections[extent].size = ISO_EXTENT_SIZE;
section_size -= (off_t) ISO_EXTENT_SIZE;
}
/*
* final section
*/
file->sections[extent].block = t->curblock + extent * (ISO_EXTENT_SIZE / BLOCK_SIZE);
file->sections[extent].size = (uint32_t)section_size;
t->curblock += DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
}
@ -243,7 +274,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
Ecma119Image *t;
IsoFileSrc *file;
IsoFileSrc **filelist;
char *name;
char name[PATH_MAX];
char buffer[BLOCK_SIZE];
if (writer == NULL) {
@ -258,23 +289,18 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
i = 0;
while ((file = filelist[i++]) != NULL) {
/*
* TODO WARNING
* when we allow files greater than 4GB, current DIV_UP implementation
* can overflow!!
*/
uint32_t nblocks = DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
res = filesrc_open(file);
iso_stream_get_file_name(file->stream, name);
if (res < 0) {
/*
/*
* UPS, very ugly error, the best we can do is just to write
* 0's to image
*/
name = iso_stream_get_name(file->stream);
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
"File \"%s\" can't be opened. Filling with 0s.", name);
free(name);
if (res < 0) {
return res; /* aborted due to error severity */
}
@ -288,11 +314,10 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
}
continue;
} else if (res > 1) {
name = iso_stream_get_name(file->stream);
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
"Size of file \"%s\" has changed. It will be %s", name,
(res == 2 ? "truncated" : "padded with 0's"));
free(name);
if (res < 0) {
filesrc_close(file);
return res; /* aborted due to error severity */
@ -300,9 +325,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
}
#ifdef LIBISOFS_VERBOSE_DEBUG
else {
name = iso_stream_get_name(file->stream);
iso_msg_debug(t->image->id, "Writing file %s", name);
free(name);
}
#endif
@ -326,7 +349,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
if (b < nblocks) {
/* premature end of file, due to error or eof */
char *name = iso_stream_get_name(file->stream);
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
if (res < 0) {
/* error */
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
@ -336,12 +359,11 @@ int filesrc_writer_write_data(IsoImageWriter *writer)
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
"Premature end of file %s.", name);
}
free(name);
if (res < 0) {
return res; /* aborted due error severity */
}
/* fill with 0s */
iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
"Filling with 0");

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#ifndef LIBISO_FILESRC_H_
@ -17,7 +17,11 @@
struct Iso_File_Src
{
unsigned int prev_img :1; /**< if the file comes from a previous image */
uint32_t block; /**< Block where this file will be written on image */
/** File Sections of the file in the image */
struct iso_file_section *sections;
int nsections;
int sort_weight;
IsoStream *stream;
};
@ -26,12 +30,12 @@ int iso_file_src_cmp(const void *n1, const void *n2);
/**
* Create a new IsoFileSrc to get data from a specific IsoFile.
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
* being written several times to image. If you call again this function
* with a node that refers to the same source file, the previously
* created one will be returned. No new IsoFileSrc is created in that case.
*
*
* @param img
* The image where this file is to be written
* @param file
@ -45,12 +49,12 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
/**
* Add a given IsoFileSrc to the given image target.
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
* being written several times to image. If you call again this function
* with a node that refers to the same source file, the previously
* created one will be returned.
*
*
* @param img
* The image where this file is to be written
* @param new
@ -58,7 +62,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
* @param src
* Will be filled with a pointer to the IsoFileSrc really present in
* the tree. It could be different than new if the same file already
* exists in the tree.
* exists in the tree.
* @return
* 1 on success, 0 if file already exists on tree, < 0 error
*/
@ -76,7 +80,7 @@ off_t iso_file_src_get_size(IsoFileSrc *file);
/**
* Create a Writer for file contents.
*
*
* It takes care of written the files in the correct order.
*/
int iso_file_src_writer_create(Ecma119Image *target);

66
libisofs/filter.c Normal file
View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2008 Vreixo Formoso
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "filter.h"
#include "node.h"
void iso_filter_ref(FilterContext *filter)
{
++filter->refcount;
}
void iso_filter_unref(FilterContext *filter)
{
if (--filter->refcount == 0) {
filter->free(filter);
free(filter);
}
}
int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag)
{
int ret;
IsoStream *original, *filtered;
if (file == NULL || filter == NULL) {
return ISO_NULL_POINTER;
}
original = file->stream;
if (!iso_stream_is_repeatable(original)) {
/* TODO use custom error */
return ISO_WRONG_ARG_VALUE;
}
ret = filter->get_filter(filter, original, &filtered);
if (ret < 0) {
return ret;
}
iso_stream_unref(original);
file->stream = filtered;
return ISO_SUCCESS;
}
int iso_file_remove_filter(IsoFile *file, int flag)
{
IsoStream *file_stream, *input_stream;
file_stream = file->stream;
input_stream = iso_stream_get_input_stream(file_stream, 0);
if (input_stream == NULL)
return 0;
file->stream = input_stream;
iso_stream_ref(input_stream); /* Protect against _unref(file_stream) */
iso_stream_unref(file_stream);
return 1;
}

75
libisofs/filter.h Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2008 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#ifndef LIBISO_FILTER_H_
#define LIBISO_FILTER_H_
/*
* Definitions of filters.
*/
/* dev_id for stream identification */
/* libisofs/filters/xor_encrypt.c */
#define XOR_ENCRYPT_DEV_ID 1
/* libisofs/filters/external.c */
#define ISO_FILTER_EXTERNAL_DEV_ID 2
/* libisofs/filters/zisofs.c */
#define ISO_FILTER_ZISOFS_DEV_ID 3
/* libisofs/filters/gzip.c */
#define ISO_FILTER_GZIP_DEV_ID 4
typedef struct filter_context FilterContext;
struct filter_context {
int version; /* reserved for future usage, set to 0 */
int refcount;
/** filter specific shared data */
void *data;
/**
* Factory method to create a filtered stream from another stream.
*
* @param original
* The original stream to be filtered. If the filter needs a ref to
* it (most cases), it should take a ref to it with iso_stream_ref().
* @param filtered
* Will be filled with the filtered IsoStream (reference belongs to
* caller).
* @return
* 1 on success, < 0 on error
*/
int (*get_filter)(FilterContext *filter, IsoStream *original,
IsoStream **filtered);
/**
* Free implementation specific data. Should never be called by user.
* Use iso_filter_unref() instead.
*/
void (*free)(FilterContext *filter);
};
/**
*
* @param flag
* Reserved for future usage, pass always 0 for now.
* TODO in a future a different value can mean filter caching, where
* the filter is applied once and the filtered file is stored in a temp
* dir. This prevent filter to be applied several times.
*/
int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag);
void iso_filter_ref(FilterContext *filter);
void iso_filter_unref(FilterContext *filter);
#endif /*LIBISO_FILTER_H_*/

780
libisofs/filters/external.c Normal file
View File

@ -0,0 +1,780 @@
/*
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*
* It implements a filter facility which can pipe a IsoStream into an external
* process, read its output and forward it as IsoStream output to an IsoFile.
* The external processes get started according to an IsoExternalFilterCommand
* which is described in libisofs.h.
*
*/
#include "../libisofs.h"
#include "../filter.h"
#include "../fsource.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#ifdef Libisofs_external_filters_selecT
#include <sys/select.h>
#endif
/*
* A filter that starts an external process and uses its stdin and stdout
* for classical pipe filtering.
*/
/*
* Individual runtime properties exist only as long as the stream is opened.
*/
typedef struct
{
int send_fd;
int recv_fd;
pid_t pid;
off_t in_counter;
int in_eof;
off_t out_counter;
int out_eof;
uint8_t pipebuf[2048]; /* buffers in case of EAGAIN on write() */
int pipebuf_fill;
} ExternalFilterRuntime;
static
int extf_running_new(ExternalFilterRuntime **running, int send_fd, int recv_fd,
pid_t child_pid, int flag)
{
ExternalFilterRuntime *o;
*running = o = calloc(sizeof(ExternalFilterRuntime), 1);
if (o == NULL) {
return ISO_OUT_OF_MEM;
}
o->send_fd = send_fd;
o->recv_fd = recv_fd;
o->pid = child_pid;
o->in_counter = 0;
o->in_eof = 0;
o->out_counter = 0;
o->out_eof = 0;
memset(o->pipebuf, 0, sizeof(o->pipebuf));
o->pipebuf_fill = 0;
return 1;
}
/*
* The data payload of an individual IsoStream from External Filter
*/
typedef struct
{
ino_t id;
IsoStream *orig;
IsoExternalFilterCommand *cmd;
off_t size; /* -1 means that the size is unknown yet */
ExternalFilterRuntime *running; /* is non-NULL when open */
} ExternalFilterStreamData;
/* Each individual ExternalFilterStreamData needs a unique id number. */
/* >>> This is very suboptimal:
The counter can rollover.
*/
static ino_t extf_ino_id = 0;
/* <<< */
static int print_fd= 0;
/*
* Methods for the IsoStreamIface of an External Filter object.
*/
/*
* @param flag bit0= original stream is not open
*/
static
int extf_stream_close_flag(IsoStream *stream, int flag)
{
int ret, status;
ExternalFilterStreamData *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->running == NULL) {
return 1;
}
/* <<< */
if (print_fd) {
fprintf(stderr, "libisofs_DEBUG: filter close in = %d , ic= %.f\n",
data->running->recv_fd, (double) data->running->in_counter);
fprintf(stderr, "libisofs_DEBUG: filter close out = %d , oc= %.f\n",
data->running->send_fd, (double) data->running->out_counter);
}
if(data->running->recv_fd != -1)
close(data->running->recv_fd);
if(data->running->send_fd != -1)
close(data->running->send_fd);
ret = waitpid(data->running->pid, &status, WNOHANG);
if (ret == 0 && data->running->pid != 0) {
kill(data->running->pid, SIGKILL);
waitpid(data->running->pid, &status, 0);
}
free(data->running);
data->running = NULL;
if (flag & 1)
return 1;
return iso_stream_close(data->orig);
}
static
int extf_stream_close(IsoStream *stream)
{
return extf_stream_close_flag(stream, 0);
}
/*
* @param flag bit0= do not run .get_size() if size is < 0
*/
static
int extf_stream_open_flag(IsoStream *stream, int flag)
{
ExternalFilterStreamData *data;
ExternalFilterRuntime *running = NULL;
pid_t child_pid;
int send_pipe[2], recv_pipe[2], ret, stream_open = 0;
send_pipe[0] = send_pipe[1] = recv_pipe[0] = recv_pipe[1] = -1;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = (ExternalFilterStreamData*)stream->data;
if (data->running != NULL) {
return ISO_FILE_ALREADY_OPENED;
}
if (data->size < 0 && !(flag & 1)) {
/* Do the size determination run now, so that the size gets cached
and .get_size() will not fail on an opened stream.
*/
stream->class->get_size(stream);
}
ret = pipe(send_pipe);
if (ret == -1) {
ret = ISO_OUT_OF_MEM;
goto parent_failed;
}
ret = pipe(recv_pipe);
if (ret == -1) {
ret = ISO_OUT_OF_MEM;
goto parent_failed;
}
child_pid= fork();
if (child_pid == -1) {
ret = ISO_DATA_SOURCE_FATAL;
goto parent_failed;
}
if (child_pid != 0) {
/* parent */
ret = extf_running_new(&running, send_pipe[1], recv_pipe[0], child_pid,
0);
if (ret < 0) {
goto parent_failed;
}
data->running = running;
/* <<< */
if (print_fd) {
fprintf(stderr, "libisofs_DEBUG: filter parent in = %d\n",
data->running->recv_fd);
fprintf(stderr, "libisofs_DEBUG: filter parent out = %d\n",
data->running->send_fd);
}
/* Give up the child-side pipe ends */
close(send_pipe[0]);
close(recv_pipe[1]);
/* Open stream only after forking so that the child does not know
the pipe inlets of eventually underlying other filter streams.
They would stay open and prevent those underlying filter children
from seeing EOF at their input.
*/
ret = iso_stream_open(data->orig);
/* <<< TEST <<<
ret= ISO_FILE_READ_ERROR;
*/
if (ret < 0) {
/* Dispose pipes and child */
extf_stream_close_flag(stream, 1);
return ret;
}
stream_open = 1;
/* Make filter outlet non-blocking */
ret = fcntl(recv_pipe[0], F_GETFL);
if (ret != -1) {
ret |= O_NONBLOCK;
fcntl(recv_pipe[0], F_SETFL, ret);
}
/* Make filter sink non-blocking */
ret = fcntl(send_pipe[1], F_GETFL);
if (ret != -1) {
ret |= O_NONBLOCK;
fcntl(send_pipe[1], F_SETFL, ret);
}
return 1;
}
/* child */
/* Give up the parent-side pipe ends */
close(send_pipe[1]);
close(recv_pipe[0]);
/* attach pipe ends to stdin and stdout */;
close(0);
ret = dup2(send_pipe[0], 0);
if (ret == -1) {
goto child_failed;
}
close(1);
ret = dup2(recv_pipe[1], 1);
if (ret == -1) {
goto child_failed;
}
/* <<< */
if (print_fd) {
fprintf(stderr, "libisofs_DEBUG: filter child in = %d\n",
send_pipe[0]);
fprintf(stderr, "libisofs_DEBUG: filter child out = %d\n",
recv_pipe[1]);
}
/* Self conversion into external program */
execv(data->cmd->path, data->cmd->argv); /* should never come back */
child_failed:;
fprintf(stderr,"--- execution of external filter command failed:\n");
fprintf(stderr," %s\n", data->cmd->path);
exit(127);
parent_failed:;
/* <<< */
if (print_fd) {
fprintf(stderr, "libisofs_DEBUG: FAILED : filter parent in = %d\n",
recv_pipe[0]);
fprintf(stderr, "libisofs_DEBUG: FAILED : filter parent out = %d\n",
send_pipe[1]);
}
if (stream_open)
iso_stream_close(data->orig);
if(send_pipe[0] != -1)
close(send_pipe[0]);
if(send_pipe[1] != -1)
close(send_pipe[1]);
if(recv_pipe[0] != -1)
close(recv_pipe[0]);
if(recv_pipe[1] != -1)
close(recv_pipe[1]);
return ret;
}
static
int extf_stream_open(IsoStream *stream)
{
return extf_stream_open_flag(stream, 0);
}
#ifdef Libisofs_external_filters_selecT
/* Performance is weaker than with non-blocking i/o and usleep(). */
static
int extf_wait_for_io(int fd_in, int fd_out, int microsec, int flag)
{
struct timeval wt;
fd_set rds,wts,exs;
int ready, fd_max;
fd_max = fd_out;
if (fd_in > fd_out)
fd_max = fd_in;
FD_ZERO(&rds);
FD_ZERO(&wts);
FD_ZERO(&exs);
if (fd_in >= 0) {
FD_SET(fd_in,&rds);
FD_SET(fd_in,&exs);
}
if (fd_out >= 0) {
FD_SET(fd_out,&rds);
FD_SET(fd_in,&exs);
}
wt.tv_sec = microsec/1000000;
wt.tv_usec = microsec%1000000;
ready = select(fd_max + 1, &rds, &wts, &exs, &wt);
if (ready <= 0)
return 0;
if (fd_in >= 0) {
if (FD_ISSET(fd_in, &rds))
return 1;
}
if (fd_out >= 0) {
if (FD_ISSET(fd_out, &rds))
return 2;
}
if (fd_in >= 0) {
if (FD_ISSET(fd_in, &exs))
return -1;
}
if (fd_out >= 0) {
if (FD_ISSET(fd_out, &exs))
return -2;
}
return(0);
}
#endif /* Libisofs_external_filters_selecT */
static
int extf_stream_read(IsoStream *stream, void *buf, size_t desired)
{
int ret, blocking = 0;
ExternalFilterStreamData *data;
ExternalFilterRuntime *running;
size_t fill = 0;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
running= data->running;
if (running == NULL) {
return ISO_FILE_NOT_OPENED;
}
if (running->out_eof) {
return 0;
}
while (1) {
if (running->in_eof && !blocking) {
/* Make filter outlet blocking */
ret = fcntl(running->recv_fd, F_GETFL);
if (ret != -1) {
ret &= ~O_NONBLOCK;
fcntl(running->recv_fd, F_SETFL, ret);
}
blocking = 1;
}
/* Try to read desired amount from filter */;
while (1) {
ret = read(running->recv_fd, ((char *) buf) + fill,
desired - fill);
if (ret < 0) {
if (errno == EAGAIN)
break;
return ISO_FILE_READ_ERROR;
}
fill += ret;
if (ret == 0) {
running->out_eof = 1;
}
if (ret == 0 || fill >= desired) {
running->out_counter += fill;
return fill;
}
}
if (running->in_eof) {
usleep(1000); /* just in case it is still non-blocking */
continue;
}
if (running->pipebuf_fill) {
ret = running->pipebuf_fill;
running->pipebuf_fill = 0;
} else {
ret = iso_stream_read(data->orig, running->pipebuf,
sizeof(running->pipebuf));
if (ret > 0)
running->in_counter += ret;
}
if (ret < 0) {
running->in_eof = 1;
return ret;
}
if (ret == 0) {
/* <<< */
if (print_fd) {
fprintf(stderr,
"libisofs_DEBUG: filter close out = %d , ic= %.f\n",
running->send_fd, (double) running->in_counter);
}
running->in_eof = 1;
close(running->send_fd); /* Tell the filter: it is over */
running->send_fd = -1;
} else {
running->pipebuf_fill = ret;
ret = write(running->send_fd, running->pipebuf,
running->pipebuf_fill);
if (ret == -1) {
if (errno == EAGAIN) {
#ifdef Libisofs_external_filters_selecT
/* This select() based waiting saves 10 % CPU load but
needs 50 % more real time */
ret = extf_wait_for_io(running->recv_fd, running->send_fd,
100000, 0);
if (ret < 0)
usleep(1000); /* To make sure sufficient laziness */
#else
/* No sleeping needs 90 % more CPU and saves 6 % time */
usleep(1000); /* go lazy because the filter is slow */
#endif /* ! Libisofs_external_filters_selecT */
continue;
}
/* From the view of the caller it _is_ a read error */
running->in_eof = 1;
return ISO_FILE_READ_ERROR;
}
running->pipebuf_fill = 0;
}
}
return ISO_FILE_READ_ERROR; /* should never be hit */
}
static
off_t extf_stream_get_size(IsoStream *stream)
{
int ret, ret_close;
off_t count = 0;
ExternalFilterStreamData *data;
char buf[64 * 1024];
size_t bufsize = 64 * 1024;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->size >= 0) {
return data->size;
}
/* Run filter command and count output bytes */
ret = extf_stream_open_flag(stream, 1);
if (ret < 0) {
return ret;
}
while (1) {
ret = extf_stream_read(stream, buf, bufsize);
if (ret <= 0)
break;
count += ret;
}
ret_close = extf_stream_close(stream);
if (ret < 0)
return ret;
if (ret_close < 0)
return ret_close;
data->size = count;
return count;
}
static
int extf_stream_is_repeatable(IsoStream *stream)
{
/* Only repeatable streams are accepted as orig */
return 1;
}
static
void extf_stream_get_id(IsoStream *stream, unsigned int *fs_id,
dev_t *dev_id, ino_t *ino_id)
{
ExternalFilterStreamData *data;
data = stream->data;
*fs_id = ISO_FILTER_FS_ID;
*dev_id = ISO_FILTER_EXTERNAL_DEV_ID;
*ino_id = data->id;
}
static
void extf_stream_free(IsoStream *stream)
{
ExternalFilterStreamData *data;
if (stream == NULL) {
return;
}
data = stream->data;
if (data->running != NULL) {
extf_stream_close(stream);
}
iso_stream_unref(data->orig);
if (data->cmd->refcount > 0)
data->cmd->refcount--;
free(data);
}
static
int extf_update_size(IsoStream *stream)
{
/* By principle size is determined only once */
return 1;
}
static
IsoStream *extf_get_input_stream(IsoStream *stream, int flag)
{
ExternalFilterStreamData *data;
if (stream == NULL) {
return NULL;
}
data = stream->data;
return data->orig;
}
static
int extf_cmp_ino(IsoStream *s1, IsoStream *s2);
/* Function is defined after definition of extf_stream_class */
IsoStreamIface extf_stream_class = {
3,
"extf",
extf_stream_open,
extf_stream_close,
extf_stream_get_size,
extf_stream_read,
extf_stream_is_repeatable,
extf_stream_get_id,
extf_stream_free,
extf_update_size,
extf_get_input_stream,
extf_cmp_ino
};
static
int extf_cmp_ino(IsoStream *s1, IsoStream *s2)
{
ExternalFilterStreamData *data1, *data2;
if (s1->class != &extf_stream_class || s2->class != &extf_stream_class)
return iso_stream_cmp_ino(s1, s2, 1);
data1 = (ExternalFilterStreamData*) s1->data;
data2 = (ExternalFilterStreamData*) s2->data;
if (data1->cmd != data2->cmd)
return (data1->cmd < data2->cmd ? -1 : 1);
return iso_stream_cmp_ino(data1->orig, data2->orig, 0);
}
/* ------------------------------------------------------------------------- */
static
void extf_filter_free(FilterContext *filter)
{
/* no data are allocated */;
}
/* To be called by iso_file_add_filter().
* The FilterContext input parameter is not furtherly needed for the
* emerging IsoStream.
*/
static
int extf_filter_get_filter(FilterContext *filter, IsoStream *original,
IsoStream **filtered)
{
IsoStream *str;
ExternalFilterStreamData *data;
IsoExternalFilterCommand *cmd;
if (filter == NULL || original == NULL || filtered == NULL) {
return ISO_NULL_POINTER;
}
cmd = (IsoExternalFilterCommand *) filter->data;
if (cmd->refcount + 1 <= 0) {
return ISO_EXTF_TOO_OFTEN;
}
str = malloc(sizeof(IsoStream));
if (str == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(ExternalFilterStreamData));
if (data == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
/* These data items are not owned by this filter object */
data->id = ++extf_ino_id;
data->orig = original;
data->cmd = cmd;
data->size = -1;
data->running = NULL;
/* get reference to the source */
iso_stream_ref(data->orig);
str->refcount = 1;
str->data = data;
str->class = &extf_stream_class;
*filtered = str;
cmd->refcount++;
return ISO_SUCCESS;
}
/* Produce a parameter object suitable for iso_file_add_filter().
* It may be disposed by free() after all those calls are made.
*
* This is an internal call of libisofs to be used by an API call that
* attaches an IsoExternalFilterCommand to one or more IsoFile objects.
* See libisofs.h for IsoExternalFilterCommand.
*/
static
int extf_create_context(IsoExternalFilterCommand *cmd,
FilterContext **filter, int flag)
{
FilterContext *f;
*filter = f = calloc(1, sizeof(FilterContext));
if (f == NULL) {
return ISO_OUT_OF_MEM;
}
f->refcount = 1;
f->version = 0;
f->data = cmd;
f->free = extf_filter_free;
f->get_filter = extf_filter_get_filter;
return ISO_SUCCESS;
}
/*
* A function which adds a filter to an IsoFile shall create a temporary
* FilterContext by iso_extf_create_context(), use it in one or more calls
* of filter.c:iso_file_add_filter() and finally dispose it by free().
*/
int iso_file_add_external_filter(IsoFile *file, IsoExternalFilterCommand *cmd,
int flag)
{
int ret;
FilterContext *f = NULL;
IsoStream *stream;
off_t original_size = 0, filtered_size = 0;
if (cmd->behavior & (1 | 2 | 4)) {
original_size = iso_file_get_size(file);
if (original_size <= 0 ||
((cmd->behavior & 4) && original_size <= 2048)) {
return 2;
}
}
ret = extf_create_context(cmd, &f, 0);
if (ret < 0) {
return ret;
}
ret = iso_file_add_filter(file, f, 0);
free(f);
if (ret < 0) {
return ret;
}
/* Run a full filter process getsize so that the size is cached */
stream = iso_file_get_stream(file);
filtered_size = iso_stream_get_size(stream);
if (filtered_size < 0) {
iso_file_remove_filter(file, 0);
return filtered_size;
}
if (((cmd->behavior & 2) && filtered_size >= original_size) ||
((cmd->behavior & 4) && filtered_size / 2048 >= original_size / 2048)){
ret = iso_file_remove_filter(file, 0);
if (ret < 0) {
return ret;
}
return 2;
}
return ISO_SUCCESS;
}
int iso_stream_get_external_filter(IsoStream *stream,
IsoExternalFilterCommand **cmd, int flag)
{
ExternalFilterStreamData *data;
if (stream->class != &extf_stream_class)
return 0;
data = stream->data;
*cmd = data->cmd;
return 1;
}

750
libisofs/filters/gzip.c Normal file
View File

@ -0,0 +1,750 @@
/*
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*
* It implements a filter facility which can pipe a IsoStream into gzip
* compression resp. uncompression, read its output and forward it as IsoStream
* output to an IsoFile.
* The gzip compression is done via zlib by Jean-loup Gailly and Mark Adler
* who state in <zlib.h>:
* "The data format used by the zlib library is described by RFCs (Request for
* Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
* (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format)."
*
*/
#include "../libisofs.h"
#include "../filter.h"
#include "../fsource.h"
#include "../util.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef Libisofs_with_zliB
#include <zlib.h>
#else
/* If zlib is not available then this code is a dummy */
#endif
/*
* A filter that encodes or decodes the content of gzip compressed files.
*/
/* --------------------------- GzipFilterRuntime ------------------------- */
/* Individual runtime properties exist only as long as the stream is opened.
*/
typedef struct
{
#ifdef Libisofs_with_zliB
z_stream strm; /* The zlib processing context */
#endif
char *in_buffer;
char *out_buffer;
int in_buffer_size;
int out_buffer_size;
char *rpt; /* out_buffer + read_bytes */
off_t in_counter;
off_t out_counter;
int do_flush; /* flush mode for deflate() changes at end of input */
int error_ret;
} GzipFilterRuntime;
static
int gzip_running_destroy(GzipFilterRuntime **running, int flag)
{
GzipFilterRuntime *o= *running;
if (o == NULL)
return 0;
if (o->in_buffer != NULL)
free(o->in_buffer);
if (o->out_buffer != NULL)
free(o->out_buffer);
free((char *) o);
*running = NULL;
return 1;
}
static
int gzip_running_new(GzipFilterRuntime **running, int flag)
{
GzipFilterRuntime *o;
*running = o = calloc(sizeof(GzipFilterRuntime), 1);
if (o == NULL) {
return ISO_OUT_OF_MEM;
}
#ifdef Libisofs_with_zliB
memset(&(o->strm), 0, sizeof(o->strm));
#endif
o->in_buffer = NULL;
o->out_buffer = NULL;
o->in_buffer_size = 0;
o->out_buffer_size = 0;
o->rpt = NULL;
o->in_counter = 0;
o->out_counter = 0;
#ifdef Libisofs_with_zliB
o->do_flush = Z_NO_FLUSH;
#endif
o->error_ret = 1;
o->in_buffer_size= 2048;
o->out_buffer_size= 2048;
o->in_buffer = calloc(o->in_buffer_size, 1);
o->out_buffer = calloc(o->out_buffer_size, 1);
if (o->in_buffer == NULL || o->out_buffer == NULL)
goto failed;
o->rpt = o->out_buffer;
return 1;
failed:
gzip_running_destroy(running, 0);
return -1;
}
/* ---------------------------- GzipFilterStreamData --------------------- */
/* Counts the number of active compression filters */
static off_t gzip_ref_count = 0;
/* Counts the number of active uncompression filters */
static off_t gunzip_ref_count = 0;
#ifdef Libisofs_with_zliB
/* Parameter for deflateInit2() , see <zlib.h> */
/* ??? get this from zisofs.c ziso_compression_level ?
* ??? have an own global parameter API ?
* For now level 6 seems to be a fine compromise between speed and size.
*/
static int gzip_compression_level = 6;
#endif /* Libisofs_with_zliB */
/*
* The data payload of an individual Gzip Filter IsoStream
*/
typedef struct
{
IsoStream *orig;
off_t size; /* -1 means that the size is unknown yet */
GzipFilterRuntime *running; /* is non-NULL when open */
ino_t id;
} GzipFilterStreamData;
/* Each individual GzipFilterStreamData needs a unique id number. */
/* >>> This is very suboptimal:
The counter can rollover.
*/
static ino_t gzip_ino_id = 0;
static
int gzip_stream_uncompress(IsoStream *stream, void *buf, size_t desired);
/*
* Methods for the IsoStreamIface of a Gzip Filter object.
*/
/*
* @param flag bit0= original stream is not open
*/
static
int gzip_stream_close_flag(IsoStream *stream, int flag)
{
#ifdef Libisofs_with_zliB
GzipFilterStreamData *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->running == NULL) {
return 1;
}
if (stream->class->read == &gzip_stream_uncompress) {
inflateEnd(&(data->running->strm));
} else {
deflateEnd(&(data->running->strm));
}
gzip_running_destroy(&(data->running), 0);
if (flag & 1)
return 1;
return iso_stream_close(data->orig);
#else
return ISO_ZLIB_NOT_ENABLED;
#endif
}
static
int gzip_stream_close(IsoStream *stream)
{
return gzip_stream_close_flag(stream, 0);
}
/*
* @param flag bit0= do not run .get_size() if size is < 0
*/
static
int gzip_stream_open_flag(IsoStream *stream, int flag)
{
#ifdef Libisofs_with_zliB
GzipFilterStreamData *data;
GzipFilterRuntime *running = NULL;
int ret;
z_stream *strm;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = (GzipFilterStreamData*) stream->data;
if (data->running != NULL) {
return ISO_FILE_ALREADY_OPENED;
}
if (data->size < 0 && !(flag & 1)) {
/* Do the size determination run now, so that the size gets cached
and .get_size() will not fail on an opened stream.
*/
stream->class->get_size(stream);
}
ret = gzip_running_new(&running,
stream->class->read == &gzip_stream_uncompress);
if (ret < 0) {
return ret;
}
data->running = running;
/* Start up zlib compression context */
strm = &(running->strm);
strm->zalloc = Z_NULL;
strm->zfree = Z_NULL;
strm->opaque = Z_NULL;
if (stream->class->read == &gzip_stream_uncompress) {
ret = inflateInit2(strm, 15 | 16);
} else {
ret = deflateInit2(strm, gzip_compression_level, Z_DEFLATED,
15 | 16, 8, Z_DEFAULT_STRATEGY);
}
if (ret != Z_OK)
return ISO_ZLIB_COMPR_ERR;
strm->next_out = (Bytef *) running->out_buffer;
strm->avail_out = running->out_buffer_size;
/* Open input stream */
ret = iso_stream_open(data->orig);
if (ret < 0) {
return ret;
}
return 1;
#else
return ISO_ZLIB_NOT_ENABLED;
#endif
}
static
int gzip_stream_open(IsoStream *stream)
{
return gzip_stream_open_flag(stream, 0);
}
/*
* @param flag bit1= uncompress rather than compress
*/
static
int gzip_stream_convert(IsoStream *stream, void *buf, size_t desired, int flag)
{
#ifdef Libisofs_with_zliB
int ret, todo, cnv_ret, c_bytes;
GzipFilterStreamData *data;
GzipFilterRuntime *rng;
size_t fill = 0;
z_stream *strm;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
rng= data->running;
if (rng == NULL) {
return ISO_FILE_NOT_OPENED;
}
strm = &(rng->strm);
if (rng->error_ret < 0) {
return rng->error_ret;
} else if (rng->error_ret == 0) {
if (rng->out_buffer_size - strm->avail_out
- (rng->rpt - rng->out_buffer) <= 0)
return 0;
}
while (1) {
/* Transfer eventual converted bytes from strm to buf */
c_bytes = rng->out_buffer_size - strm->avail_out
- (rng->rpt - rng->out_buffer);
if (c_bytes > 0) {
todo = desired - fill;
if (todo > c_bytes)
todo = c_bytes;
memcpy(((char *) buf) + fill, rng->rpt, todo);
rng->rpt += todo;
fill += todo;
rng->out_counter += todo;
}
if (fill >= desired || rng->error_ret == 0)
return fill;
/* All buffered out data are consumed now */
rng->rpt = rng->out_buffer;
strm->next_out = (Bytef *) rng->out_buffer;
strm->avail_out = rng->out_buffer_size;
if (strm->avail_in == 0) {
/* All pending input is consumed. Get new input. */
ret = iso_stream_read(data->orig, rng->in_buffer,
rng->in_buffer_size);
if (ret < 0)
return (rng->error_ret = ret);
if (ret == 0) {
if (flag & 2) {
/* Early input EOF */
return (rng->error_ret = ISO_ZLIB_EARLY_EOF);
} else {
/* Tell zlib by the next call that it is over */
rng->do_flush = Z_FINISH;
}
}
strm->next_in = (Bytef *) rng->in_buffer;
strm->avail_in = ret;
rng->in_counter += ret;
}
/* Submit input and fetch output until input is consumed */
while (1) {
if (flag & 2) {
cnv_ret = inflate(strm, rng->do_flush);
} else {
cnv_ret = deflate(strm, rng->do_flush);
}
if (cnv_ret == Z_STREAM_ERROR || cnv_ret == Z_BUF_ERROR) {
return (rng->error_ret = ISO_ZLIB_COMPR_ERR);
}
if (strm->avail_out < rng->out_buffer_size)
break; /* output is available */
if (strm->avail_in == 0) /* all pending input consumed */
break;
}
if (cnv_ret == Z_STREAM_END)
rng->error_ret = 0;
}
return fill;
#else
return ISO_ZLIB_NOT_ENABLED;
#endif
}
static
int gzip_stream_compress(IsoStream *stream, void *buf, size_t desired)
{
return gzip_stream_convert(stream, buf, desired, 0);
}
static
int gzip_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
{
return gzip_stream_convert(stream, buf, desired, 2);
}
static
off_t gzip_stream_get_size(IsoStream *stream)
{
int ret, ret_close;
off_t count = 0;
GzipFilterStreamData *data;
char buf[64 * 1024];
size_t bufsize = 64 * 1024;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
if (data->size >= 0) {
return data->size;
}
/* Run filter command and count output bytes */
ret = gzip_stream_open_flag(stream, 1);
if (ret < 0) {
return ret;
}
while (1) {
ret = stream->class->read(stream, buf, bufsize);
if (ret <= 0)
break;
count += ret;
}
ret_close = gzip_stream_close(stream);
if (ret < 0)
return ret;
if (ret_close < 0)
return ret_close;
data->size = count;
return count;
}
static
int gzip_stream_is_repeatable(IsoStream *stream)
{
/* Only repeatable streams are accepted as orig */
return 1;
}
static
void gzip_stream_get_id(IsoStream *stream, unsigned int *fs_id,
dev_t *dev_id, ino_t *ino_id)
{
GzipFilterStreamData *data;
data = stream->data;
*fs_id = ISO_FILTER_FS_ID;
*dev_id = ISO_FILTER_GZIP_DEV_ID;
*ino_id = data->id;
}
static
void gzip_stream_free(IsoStream *stream)
{
GzipFilterStreamData *data;
if (stream == NULL) {
return;
}
data = stream->data;
if (data->running != NULL) {
gzip_stream_close(stream);
}
if (stream->class->read == &gzip_stream_uncompress) {
if (--gunzip_ref_count < 0)
gunzip_ref_count = 0;
} else {
if (--gzip_ref_count < 0)
gzip_ref_count = 0;
}
iso_stream_unref(data->orig);
free(data);
}
static
int gzip_update_size(IsoStream *stream)
{
/* By principle size is determined only once */
return 1;
}
static
IsoStream *gzip_get_input_stream(IsoStream *stream, int flag)
{
GzipFilterStreamData *data;
if (stream == NULL) {
return NULL;
}
data = stream->data;
return data->orig;
}
static
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2);
IsoStreamIface gzip_stream_compress_class = {
3,
"gzip",
gzip_stream_open,
gzip_stream_close,
gzip_stream_get_size,
gzip_stream_compress,
gzip_stream_is_repeatable,
gzip_stream_get_id,
gzip_stream_free,
gzip_update_size,
gzip_get_input_stream,
gzip_cmp_ino
};
IsoStreamIface gzip_stream_uncompress_class = {
3,
"pizg",
gzip_stream_open,
gzip_stream_close,
gzip_stream_get_size,
gzip_stream_uncompress,
gzip_stream_is_repeatable,
gzip_stream_get_id,
gzip_stream_free,
gzip_update_size,
gzip_get_input_stream,
gzip_cmp_ino
};
static
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2)
{
if (s1->class != s2->class || (s1->class != &gzip_stream_compress_class &&
s2->class != &gzip_stream_compress_class))
return iso_stream_cmp_ino(s1, s2, 1);
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
iso_stream_get_input_stream(s2, 0), 0);
}
/* ------------------------------------------------------------------------- */
static
void gzip_filter_free(FilterContext *filter)
{
/* no data are allocated */;
}
/*
* @param flag bit1= Install a decompression filter
*/
static
int gzip_filter_get_filter(FilterContext *filter, IsoStream *original,
IsoStream **filtered, int flag)
{
IsoStream *str;
GzipFilterStreamData *data;
if (filter == NULL || original == NULL || filtered == NULL) {
return ISO_NULL_POINTER;
}
str = calloc(sizeof(IsoStream), 1);
if (str == NULL) {
return ISO_OUT_OF_MEM;
}
data = calloc(sizeof(GzipFilterStreamData), 1);
if (data == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
/* These data items are not owned by this filter object */
data->id = ++gzip_ino_id;
data->orig = original;
data->size = -1;
data->running = NULL;
/* get reference to the source */
iso_stream_ref(data->orig);
str->refcount = 1;
str->data = data;
if (flag & 2) {
str->class = &gzip_stream_uncompress_class;
gunzip_ref_count++;
} else {
str->class = &gzip_stream_compress_class;
gzip_ref_count++;
}
*filtered = str;
return ISO_SUCCESS;
}
/* To be called by iso_file_add_filter().
* The FilterContext input parameter is not furtherly needed for the
* emerging IsoStream.
*/
static
int gzip_filter_get_compressor(FilterContext *filter, IsoStream *original,
IsoStream **filtered)
{
return gzip_filter_get_filter(filter, original, filtered, 0);
}
static
int gzip_filter_get_uncompressor(FilterContext *filter, IsoStream *original,
IsoStream **filtered)
{
return gzip_filter_get_filter(filter, original, filtered, 2);
}
/* Produce a parameter object suitable for iso_file_add_filter().
* It may be disposed by free() after all those calls are made.
*
* This is quite a dummy as it does not carry individual data.
* @param flag bit1= Install a decompression filter
*/
static
int gzip_create_context(FilterContext **filter, int flag)
{
FilterContext *f;
*filter = f = calloc(1, sizeof(FilterContext));
if (f == NULL) {
return ISO_OUT_OF_MEM;
}
f->refcount = 1;
f->version = 0;
f->data = NULL;
f->free = gzip_filter_free;
if (flag & 2)
f->get_filter = gzip_filter_get_uncompressor;
else
f->get_filter = gzip_filter_get_compressor;
return ISO_SUCCESS;
}
/*
* @param flag bit0= if_block_reduction rather than if_reduction
* bit1= Install a decompression filter
* bit2= only inquire availability of gzip filtering
* bit3= do not inquire size
*/
int gzip_add_filter(IsoFile *file, int flag)
{
#ifdef Libisofs_with_zliB
int ret;
FilterContext *f = NULL;
IsoStream *stream;
off_t original_size = 0, filtered_size = 0;
if (flag & 4)
return 2;
original_size = iso_file_get_size(file);
ret = gzip_create_context(&f, flag & 2);
if (ret < 0) {
return ret;
}
ret = iso_file_add_filter(file, f, 0);
free(f);
if (ret < 0) {
return ret;
}
if (flag & 8) /* size will be filled in by caller */
return ISO_SUCCESS;
/* Run a full filter process getsize so that the size is cached */
stream = iso_file_get_stream(file);
filtered_size = iso_stream_get_size(stream);
if (filtered_size < 0) {
iso_file_remove_filter(file, 0);
return filtered_size;
}
if ((filtered_size >= original_size ||
((flag & 1) && filtered_size / 2048 >= original_size / 2048))
&& !(flag & 2)){
ret = iso_file_remove_filter(file, 0);
if (ret < 0) {
return ret;
}
return 2;
}
return ISO_SUCCESS;
#else
return ISO_ZLIB_NOT_ENABLED;
#endif /* ! Libisofs_with_zliB */
}
/* API function */
int iso_file_add_gzip_filter(IsoFile *file, int flag)
{
return gzip_add_filter(file, flag & ~8);
}
/* API function */
int iso_gzip_get_refcounts(off_t *gzip_count, off_t *gunzip_count, int flag)
{
*gzip_count = gzip_ref_count;
*gunzip_count = gunzip_ref_count;
return ISO_SUCCESS;
}

View File

@ -0,0 +1,187 @@
/*
* Copyright (c) 2008 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "../libisofs.h"
#include "../filter.h"
#include "../fsource.h"
/*
* A simple Filter implementation for example purposes. It encrypts a file
* by XORing each byte by a given key.
*/
static ino_t xor_ino_id = 0;
typedef struct
{
IsoStream *orig;
uint8_t key;
ino_t id;
} XorEncryptStreamData;
static
int xor_encrypt_stream_open(IsoStream *stream)
{
XorEncryptStreamData *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = (XorEncryptStreamData*)stream->data;
return iso_stream_open(data->orig);
}
static
int xor_encrypt_stream_close(IsoStream *stream)
{
XorEncryptStreamData *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
return iso_stream_close(data->orig);
}
static
off_t xor_encrypt_stream_get_size(IsoStream *stream)
{
XorEncryptStreamData *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
return iso_stream_get_size(data->orig);
}
static
int xor_encrypt_stream_read(IsoStream *stream, void *buf, size_t count)
{
int ret, len;
XorEncryptStreamData *data;
uint8_t *buffer = buf;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
ret = iso_stream_read(data->orig, buf, count);
if (ret < 0) {
return ret;
}
/* xor */
for (len = 0; len < ret; ++len) {
buffer[len] = buffer[len] ^ data->key;
}
return ret;
}
static
int xor_encrypt_stream_is_repeatable(IsoStream *stream)
{
/* the filter can't be created if underlying stream is not repeatable */
return 1;
}
static
void xor_encrypt_stream_get_id(IsoStream *stream, unsigned int *fs_id,
dev_t *dev_id, ino_t *ino_id)
{
XorEncryptStreamData *data = stream->data;
*fs_id = ISO_FILTER_FS_ID;
*dev_id = XOR_ENCRYPT_DEV_ID;
*ino_id = data->id;
}
static
void xor_encrypt_stream_free(IsoStream *stream)
{
XorEncryptStreamData *data = stream->data;
iso_stream_unref(data->orig);
free(data);
}
IsoStreamIface xor_encrypt_stream_class = {
0,
"xorf",
xor_encrypt_stream_open,
xor_encrypt_stream_close,
xor_encrypt_stream_get_size,
xor_encrypt_stream_read,
xor_encrypt_stream_is_repeatable,
xor_encrypt_stream_get_id,
xor_encrypt_stream_free
};
static
void xor_encrypt_filter_free(FilterContext *filter)
{
free(filter->data);
}
static
int xor_encrypt_filter_get_filter(FilterContext *filter, IsoStream *original,
IsoStream **filtered)
{
IsoStream *str;
XorEncryptStreamData *data;
if (filter == NULL || original == NULL || filtered == NULL) {
return ISO_NULL_POINTER;
}
str = malloc(sizeof(IsoStream));
if (str == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(XorEncryptStreamData));
if (str == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
/* fill data */
data->key = *((uint8_t*)filter->data);
data->id = xor_ino_id++;
/* get reference to the source */
data->orig = original;
iso_stream_ref(original);
str->refcount = 1;
str->data = data;
str->class = &xor_encrypt_stream_class;
*filtered = str;
return ISO_SUCCESS;
}
int create_xor_encrypt_filter(uint8_t key, FilterContext **filter)
{
FilterContext *f;
uint8_t *data;
f = calloc(1, sizeof(FilterContext));
if (f == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(uint8_t));
if (data == NULL) {
free(f);
return ISO_OUT_OF_MEM;
}
f->refcount = 1;
f->version = 0;
*data = key;
f->data = data;
f->free = xor_encrypt_filter_free;
f->get_filter = xor_encrypt_filter_get_filter;
return ISO_SUCCESS;
}

1149
libisofs/filters/zisofs.c Normal file

File diff suppressed because it is too large Load Diff

761
libisofs/find.c Normal file
View File

@ -0,0 +1,761 @@
/*
* Copyright (c) 2008 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "node.h"
#include <fnmatch.h>
#include <string.h>
struct iso_find_condition
{
/*
* Check whether the given node matches this condition.
*
* @param cond
* The condition to check
* @param node
* The node that should be checked
* @return
* 1 if the node matches the condition, 0 if not
*/
int (*matches)(IsoFindCondition *cond, IsoNode *node);
/**
* Free condition specific data
*/
void (*free)(IsoFindCondition*);
/** condition specific data */
void *data;
};
struct find_iter_data
{
IsoDir *dir; /**< original dir of the iterator */
IsoDirIter *iter;
IsoDirIter *itersec; /**< iterator to deal with child dirs */
IsoFindCondition *cond;
int err; /**< error? */
IsoNode *current; /**< node to be returned next */
IsoNode *prev; /**< last returned node, needed for removal */
int free_cond; /**< whether to free cond on iter_free */
};
static
int get_next(struct find_iter_data *iter, IsoNode **n)
{
int ret;
if (iter->itersec != NULL) {
ret = iso_dir_iter_next(iter->itersec, n);
if (ret <= 0) {
/* secondary item no more needed */
iso_dir_iter_free(iter->itersec);
iter->itersec = NULL;
}
if (ret != 0) {
/* succes or error */
return ret;
}
}
/*
* we reach here if:
* - no secondary item is present
* - secondary item has no more items
*/
while ((ret = iso_dir_iter_next(iter->iter, n)) == 1) {
if (iter->cond->matches(iter->cond, *n)) {
return ISO_SUCCESS;
} else if (ISO_NODE_IS_DIR(*n)) {
/* recurse on child dir */
struct find_iter_data *data;
ret = iso_dir_find_children((IsoDir*)*n, iter->cond,
&iter->itersec);
if (ret < 0) {
return ret;
}
data = iter->itersec->data;
data->free_cond = 0; /* we don't need sec iter to free cond */
return get_next(iter, n);
}
}
return ret;
}
static
void update_next(IsoDirIter *iter)
{
int ret;
IsoNode *n;
struct find_iter_data *data = iter->data;
if (data->prev) {
iso_node_unref(data->prev);
}
data->prev = data->current;
if (data->itersec == NULL && data->current != NULL
&& ISO_NODE_IS_DIR(data->current)) {
/* we need to recurse on child dir */
struct find_iter_data *data2;
ret = iso_dir_find_children((IsoDir*)data->current, data->cond,
&data->itersec);
if (ret < 0) {
data->current = NULL;
data->err = ret;
return;
}
data2 = data->itersec->data;
data2->free_cond = 0; /* we don't need sec iter to free cond */
}
ret = get_next(data, &n);
iso_node_unref((IsoNode*)iter->dir);
if (ret == 1) {
data->current = n;
iso_node_ref(n);
data->err = 0;
iter->dir = n->parent;
} else {
data->current = NULL;
data->err = ret;
iter->dir = data->dir;
}
iso_node_ref((IsoNode*)iter->dir);
}
static
int find_iter_next(IsoDirIter *iter, IsoNode **node)
{
struct find_iter_data *data = iter->data;
if (iter == NULL || node == NULL) {
return ISO_NULL_POINTER;
}
if (data->err < 0) {
return data->err;
}
*node = data->current;
update_next(iter);
return (*node == NULL) ? 0 : ISO_SUCCESS;
}
static
int find_iter_has_next(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
return (data->current != NULL);
}
static
void find_iter_free(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
if (data->free_cond) {
data->cond->free(data->cond);
free(data->cond);
}
iso_node_unref((IsoNode*)data->dir);
/* free refs to nodes */
if (data->prev) {
iso_node_unref(data->prev);
}
if (data->current) {
iso_node_unref(data->current);
}
/* free underlying iter */
iso_dir_iter_free(data->iter);
free(iter->data);
}
static
int find_iter_take(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
if (data->prev == NULL) {
return ISO_ERROR; /* next not called or end of dir */
}
return iso_node_take(data->prev);
}
static
int find_iter_remove(IsoDirIter *iter)
{
struct find_iter_data *data = iter->data;
if (data->prev == NULL) {
return ISO_ERROR; /* next not called or end of dir */
}
return iso_node_remove(data->prev);
}
void find_notify_child_taken(IsoDirIter *iter, IsoNode *node)
{
struct find_iter_data *data = iter->data;
if (data->prev == node) {
/* free our ref */
iso_node_unref(node);
data->prev = NULL;
} else if (data->current == node) {
iso_node_unref(node);
data->current = NULL;
update_next(iter);
}
}
static
struct iso_dir_iter_iface find_iter_class = {
find_iter_next,
find_iter_has_next,
find_iter_free,
find_iter_take,
find_iter_remove,
find_notify_child_taken
};
int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond,
IsoDirIter **iter)
{
int ret;
IsoDirIter *children;
IsoDirIter *it;
struct find_iter_data *data;
if (dir == NULL || cond == NULL || iter == NULL) {
return ISO_NULL_POINTER;
}
it = malloc(sizeof(IsoDirIter));
if (it == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(struct find_iter_data));
if (data == NULL) {
free(it);
return ISO_OUT_OF_MEM;
}
ret = iso_dir_get_children(dir, &children);
if (ret < 0) {
free(it);
free(data);
return ret;
}
it->class = &find_iter_class;
it->dir = (IsoDir*)dir;
data->iter = children;
data->itersec = NULL;
data->cond = cond;
data->free_cond = 1;
data->err = 0;
data->prev = data->current = NULL;
it->data = data;
if (iso_dir_iter_register(it) < 0) {
free(it);
return ISO_OUT_OF_MEM;
}
iso_node_ref((IsoNode*)dir);
/* take another ref to the original dir */
data->dir = (IsoDir*)dir;
iso_node_ref((IsoNode*)dir);
update_next(it);
*iter = it;
return ISO_SUCCESS;
}
/*************** find by name wildcard condition *****************/
static
int cond_name_matches(IsoFindCondition *cond, IsoNode *node)
{
char *pattern = (char*) cond->data;
int ret = fnmatch(pattern, node->name, 0);
return ret == 0 ? 1 : 0;
}
static
void cond_name_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks if the node name matches the given
* wildcard.
*
* @param wildcard
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_name(const char *wildcard)
{
IsoFindCondition *cond;
if (wildcard == NULL) {
return NULL;
}
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
cond->data = strdup(wildcard);
cond->free = cond_name_free;
cond->matches = cond_name_matches;
return cond;
}
/*************** find by mode condition *****************/
static
int cond_mode_matches(IsoFindCondition *cond, IsoNode *node)
{
mode_t *mask = (mode_t*) cond->data;
return node->mode & *mask ? 1 : 0;
}
static
void cond_mode_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the node mode against a mode mask. It
* can be used to check both file type and permissions.
*
* For example:
*
* iso_new_find_conditions_mode(S_IFREG) : search for regular files
* iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character
* devices where owner has write permissions.
*
* @param mask
* Mode mask to AND against node mode.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_mode(mode_t mask)
{
IsoFindCondition *cond;
mode_t *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(mode_t));
if (data == NULL) {
free(cond);
return NULL;
}
*data = mask;
cond->data = data;
cond->free = cond_mode_free;
cond->matches = cond_mode_matches;
return cond;
}
/*************** find by gid condition *****************/
static
int cond_gid_matches(IsoFindCondition *cond, IsoNode *node)
{
gid_t *gid = (gid_t*) cond->data;
return node->gid == *gid ? 1 : 0;
}
static
void cond_gid_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the node gid.
*
* @param gid
* Desired Group Id.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_gid(gid_t gid)
{
IsoFindCondition *cond;
gid_t *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(gid_t));
if (data == NULL) {
free(cond);
return NULL;
}
*data = gid;
cond->data = data;
cond->free = cond_gid_free;
cond->matches = cond_gid_matches;
return cond;
}
/*************** find by uid condition *****************/
static
int cond_uid_matches(IsoFindCondition *cond, IsoNode *node)
{
uid_t *uid = (uid_t*) cond->data;
return node->uid == *uid ? 1 : 0;
}
static
void cond_uid_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the node uid.
*
* @param uid
* Desired User Id.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_uid(uid_t uid)
{
IsoFindCondition *cond;
uid_t *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(uid_t));
if (data == NULL) {
free(cond);
return NULL;
}
*data = uid;
cond->data = data;
cond->free = cond_uid_free;
cond->matches = cond_uid_matches;
return cond;
}
/*************** find by timestamps condition *****************/
struct cond_times
{
time_t time;
int what_time; /* 0 atime, 1 mtime, 2 ctime */
enum iso_find_comparisons comparison;
};
static
int cond_time_matches(IsoFindCondition *cond, IsoNode *node)
{
time_t node_time;
struct cond_times *data = cond->data;
switch (data->what_time) {
case 0: node_time = node->atime; break;
case 1: node_time = node->mtime; break;
default: node_time = node->ctime; break;
}
switch (data->comparison) {
case ISO_FIND_COND_GREATER:
return node_time > data->time ? 1 : 0;
case ISO_FIND_COND_GREATER_OR_EQUAL:
return node_time >= data->time ? 1 : 0;
case ISO_FIND_COND_EQUAL:
return node_time == data->time ? 1 : 0;
case ISO_FIND_COND_LESS:
return node_time < data->time ? 1 : 0;
case ISO_FIND_COND_LESS_OR_EQUAL:
return node_time <= data->time ? 1 : 0;
}
/* should never happen */
return 0;
}
static
void cond_time_free(IsoFindCondition *cond)
{
free(cond->data);
}
/**
* Create a new condition that checks the time of last access.
*
* @param time
* Time to compare against IsoNode atime.
* @param comparison
* Comparison to be done between IsoNode atime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_atime(time_t time,
enum iso_find_comparisons comparison)
{
IsoFindCondition *cond;
struct cond_times *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct cond_times));
if (data == NULL) {
free(cond);
return NULL;
}
data->time = time;
data->comparison = comparison;
data->what_time = 0; /* atime */
cond->data = data;
cond->free = cond_time_free;
cond->matches = cond_time_matches;
return cond;
}
/**
* Create a new condition that checks the time of last modification.
*
* @param time
* Time to compare against IsoNode mtime.
* @param comparison
* Comparison to be done between IsoNode mtime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_mtime(time_t time,
enum iso_find_comparisons comparison)
{
IsoFindCondition *cond;
struct cond_times *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct cond_times));
if (data == NULL) {
free(cond);
return NULL;
}
data->time = time;
data->comparison = comparison;
data->what_time = 1; /* mtime */
cond->data = data;
cond->free = cond_time_free;
cond->matches = cond_time_matches;
return cond;
}
/**
* Create a new condition that checks the time of last status change.
*
* @param time
* Time to compare against IsoNode ctime.
* @param comparison
* Comparison to be done between IsoNode ctime and submitted time.
* Note that ISO_FIND_COND_GREATER, for example, is true if the node
* time is greater than the submitted time.
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_ctime(time_t time,
enum iso_find_comparisons comparison)
{
IsoFindCondition *cond;
struct cond_times *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct cond_times));
if (data == NULL) {
free(cond);
return NULL;
}
data->time = time;
data->comparison = comparison;
data->what_time = 2; /* ctime */
cond->data = data;
cond->free = cond_time_free;
cond->matches = cond_time_matches;
return cond;
}
/*************** logical operations on conditions *****************/
struct logical_binary_conditions {
IsoFindCondition *a;
IsoFindCondition *b;
};
static
void cond_logical_binary_free(IsoFindCondition *cond)
{
struct logical_binary_conditions *data;
data = cond->data;
data->a->free(data->a);
free(data->a);
data->b->free(data->b);
free(data->b);
free(cond->data);
}
static
int cond_logical_and_matches(IsoFindCondition *cond, IsoNode *node)
{
struct logical_binary_conditions *data = cond->data;
return data->a->matches(data->a, node) && data->b->matches(data->b, node);
}
/**
* Create a new condition that check if the two given conditions are
* valid.
*
* @param a
* @param b
* IsoFindCondition to compare
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a,
IsoFindCondition *b)
{
IsoFindCondition *cond;
struct logical_binary_conditions *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct logical_binary_conditions));
if (data == NULL) {
free(cond);
return NULL;
}
data->a = a;
data->b = b;
cond->data = data;
cond->free = cond_logical_binary_free;
cond->matches = cond_logical_and_matches;
return cond;
}
static
int cond_logical_or_matches(IsoFindCondition *cond, IsoNode *node)
{
struct logical_binary_conditions *data = cond->data;
return data->a->matches(data->a, node) || data->b->matches(data->b, node);
}
/**
* Create a new condition that check if at least one the two given conditions
* is valid.
*
* @param a
* @param b
* IsoFindCondition to compare
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a,
IsoFindCondition *b)
{
IsoFindCondition *cond;
struct logical_binary_conditions *data;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
data = malloc(sizeof(struct logical_binary_conditions));
if (data == NULL) {
free(cond);
return NULL;
}
data->a = a;
data->b = b;
cond->data = data;
cond->free = cond_logical_binary_free;
cond->matches = cond_logical_or_matches;
return cond;
}
static
void cond_not_free(IsoFindCondition *cond)
{
IsoFindCondition *negate = cond->data;
negate->free(negate);
free(negate);
}
static
int cond_not_matches(IsoFindCondition *cond, IsoNode *node)
{
IsoFindCondition *negate = cond->data;
return !(negate->matches(negate, node));
}
/**
* Create a new condition that check if the given conditions is false.
*
* @param negate
* @result
* The created IsoFindCondition, NULL on error.
*
* @since 0.6.4
*/
IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate)
{
IsoFindCondition *cond;
cond = malloc(sizeof(IsoFindCondition));
if (cond == NULL) {
return NULL;
}
cond->data = negate;
cond->free = cond_not_free;
cond->matches = cond_not_matches;
return cond;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
@ -12,6 +13,7 @@
#include "fsource.h"
#include "util.h"
#include "aaip_0_2.h"
#include <stdlib.h>
#include <sys/types.h>
@ -32,6 +34,7 @@ int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
*/
IsoFilesystem *lfs= NULL;
typedef struct
{
/** reference to the parent (if root it points to itself) */
@ -190,7 +193,7 @@ int lfs_open(IsoFileSource *src)
data = src->data;
if (data->openned) {
return ISO_FILE_ALREADY_OPENNED;
return ISO_FILE_ALREADY_OPENED;
}
/* is a file or a dir ? */
@ -251,7 +254,7 @@ int lfs_close(IsoFileSource *src)
ret = closedir(data->info.dir) == 0 ? ISO_SUCCESS : ISO_FILE_ERROR;
break;
default:
ret = ISO_FILE_NOT_OPENNED;
ret = ISO_FILE_NOT_OPENED;
break;
}
if (ret == ISO_SUCCESS) {
@ -300,7 +303,53 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count)
case 2: /* directory */
return ISO_FILE_IS_DIR;
default:
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
}
static
off_t lfs_lseek(IsoFileSource *src, off_t offset, int flag)
{
_LocalFsFileSource *data;
int whence;
if (src == NULL) {
return (off_t)ISO_NULL_POINTER;
}
switch (flag) {
case 0:
whence = SEEK_SET; break;
case 1:
whence = SEEK_CUR; break;
case 2:
whence = SEEK_END; break;
default:
return (off_t)ISO_WRONG_ARG_VALUE;
}
data = src->data;
switch (data->openned) {
case 1: /* not dir */
{
off_t ret;
ret = lseek(data->info.fd, offset, whence);
if (ret < 0) {
/* error on read */
switch (errno) {
case ESPIPE:
ret = (off_t)ISO_FILE_ERROR;
break;
default:
ret = (off_t)ISO_ERROR;
break;
}
}
return ret;
}
case 2: /* directory */
return (off_t)ISO_FILE_IS_DIR;
default:
return (off_t)ISO_FILE_NOT_OPENED;
}
}
@ -341,7 +390,7 @@ int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
return ret;
}
default:
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
}
@ -420,8 +469,60 @@ void lfs_free(IsoFileSource *src)
iso_filesystem_unref(lfs);
}
static
int lfs_get_aa_string(IsoFileSource *src, unsigned char **aa_string, int flag)
{
int ret;
size_t num_attrs = 0, *value_lengths = NULL, result_len, sret;
char *path = NULL, **names = NULL, **values = NULL;
unsigned char *result = NULL;
_LocalFsFileSource *data;
data = src->data;
*aa_string = NULL;
if ((flag & 3 ) == 3) {
ret = 1;
goto ex;
}
/* Obtain EAs and ACLs ("access" and "default"). ACLs encoded according
to AAIP ACL representation. Clean out st_mode ACL entries.
*/
path = iso_file_source_get_path(src);
ret = aaip_get_attr_list(path, &num_attrs, &names,
&value_lengths, &values,
(!(flag & 2)) | 2 | (flag & 4) | 16);
if (ret <= 0) {
ret = ISO_FILE_ERROR;
goto ex;
}
if (num_attrs == 0)
result = NULL;
else {
sret = aaip_encode(num_attrs, names,
value_lengths, values, &result_len, &result, 0);
if (sret == 0) {
ret = ISO_OUT_OF_MEM;
goto ex;
}
}
*aa_string = result;
ret = 1;
ex:;
if (path != NULL)
free(path);
if (names != NULL || value_lengths != NULL || values != NULL)
aaip_get_attr_list(path, &num_attrs, &names, &value_lengths, &values,
1 << 15); /* free memory */
return ret;
}
IsoFileSourceIface lfs_class = {
0, /* version */
1, /* version */
lfs_get_path,
lfs_get_name,
lfs_lstat,
@ -433,9 +534,13 @@ IsoFileSourceIface lfs_class = {
lfs_readdir,
lfs_readlink,
lfs_get_filesystem,
lfs_free
lfs_free,
lfs_lseek,
lfs_get_aa_string
};
/**
*
* @return
@ -643,3 +748,78 @@ int iso_local_filesystem_new(IsoFilesystem **fs)
*fs = lfs;
return ISO_SUCCESS;
}
int iso_local_get_acl_text(char *disk_path, char **text, int flag)
{
int ret;
ret = aaip_get_acl_text(disk_path, text, flag & (1 | 16 | 32 | (1 << 15)));
return ret;
}
int iso_local_set_acl_text(char *disk_path, char *text, int flag)
{
int ret;
ret = aaip_set_acl_text(disk_path, text, flag & (1 | 32));
if (ret < 0)
return ISO_AAIP_NO_SET_LOCAL;
return ret;
}
int iso_local_get_attrs(char *disk_path, size_t *num_attrs, char ***names,
size_t **value_lengths, char ***values, int flag)
{
int ret;
ret = aaip_get_attr_list(disk_path,
num_attrs, names, value_lengths, values,
(flag & (1 | 4 | 8 | 32 | (1 << 15))) | 2 | 16);
if (ret <= 0)
return ISO_AAIP_NO_GET_LOCAL;
return 1;
}
int iso_local_set_attrs(char *disk_path, size_t num_attrs, char **names,
size_t *value_lengths, char **values, int flag)
{
int ret;
ret = aaip_set_attr_list(disk_path, num_attrs, names, value_lengths,
values, (flag & (8 | 32)) | !(flag & 1));
if (ret <= 0) {
if (ret == -1)
return ISO_OUT_OF_MEM;
if (ret == -2)
return ISO_AAIP_BAD_AASTRING;
return ISO_AAIP_NO_SET_LOCAL;
}
return 1;
}
int iso_local_get_perms_wo_acl(char *disk_path, mode_t *st_mode, int flag)
{
struct stat stbuf;
int ret;
char *a_text = NULL;
if (flag & 32)
ret = stat(disk_path, &stbuf);
else
ret = lstat(disk_path, &stbuf);
if (ret == -1)
return -1;
*st_mode = stbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
ret = iso_local_get_acl_text(disk_path, &a_text, 16 | (flag & 32));
if (a_text != NULL) {
aaip_cleanout_st_mode(a_text, st_mode, 4 | 16);
iso_local_get_acl_text(disk_path, &a_text, 1 << 15); /* free a_text */
}
return 1;
}

View File

@ -92,6 +92,12 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count)
return src->class->read(src, buf, count);
}
inline
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag)
{
return src->class->lseek(src, offset, flag);
}
inline
int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child)
{
@ -109,3 +115,16 @@ IsoFilesystem* iso_file_source_get_filesystem(IsoFileSource *src)
{
return src->class->get_filesystem(src);
}
inline
int iso_file_source_get_aa_string(IsoFileSource *src,
unsigned char **aa_string, int flag)
{
if (src->class->version < 1) {
*aa_string = NULL;
return 1;
}
return src->class->get_aa_string(src, aa_string, flag);
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
@ -20,6 +21,7 @@
#define ISO_IMAGE_FS_ID 2
#define ISO_ELTORITO_FS_ID 3
#define ISO_MEM_FS_ID 4
#define ISO_FILTER_FS_ID 5
/**
* Create a new IsoFilesystem to deal with local filesystem.
@ -29,4 +31,10 @@
*/
int iso_local_filesystem_new(IsoFilesystem **fs);
/* Rank two IsoFileSource by their eventual old image LBAs.
Other IsoFileSource classes will be ranked only roughly.
*/
int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int flag);
#endif /*LIBISO_FSOURCE_H_*/

View File

@ -1,8 +1,9 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -14,12 +15,13 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/**
* Create a new image, empty.
*
*
* The image will be owned by you and should be unref() when no more needed.
*
*
* @param name
* Name of the image. This will be used as volset_id and volume_id.
* @param image
@ -71,6 +73,11 @@ int iso_image_new(const char *name, IsoImage **image)
img->volset_id = strdup(name);
img->volume_id = strdup(name);
}
img->builder_ignore_acl = 1;
img->builder_ignore_ea = 1;
img->inode_counter = 0;
img->used_inodes = NULL;
img->used_inodes_start = 0;
*image = img;
return ISO_SUCCESS;
}
@ -85,7 +92,7 @@ void iso_image_ref(IsoImage *image)
/**
* Decrements the reference couting of the given image.
* If it reaches 0, the image is free, together with its tree nodes (whether
* If it reaches 0, the image is free, together with its tree nodes (whether
* their refcount reach 0 too, of course).
*/
void iso_image_unref(IsoImage *image)
@ -117,6 +124,8 @@ void iso_image_unref(IsoImage *image)
free(image->copyright_file_id);
free(image->abstract_file_id);
free(image->biblio_file_id);
if (image->used_inodes != NULL)
free(image->used_inodes);
free(image);
}
}
@ -125,7 +134,7 @@ void iso_image_unref(IsoImage *image)
* Attach user defined data to the image. Use this if your application needs
* to store addition info together with the IsoImage. If the image already
* has data attached, the old data will be freed.
*
*
* @param data
* Pointer to application defined data that will be attached to the
* image. You can pass NULL to remove any already attached data.
@ -139,7 +148,7 @@ int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
if (image == NULL || (data != NULL && free == NULL)) {
return ISO_NULL_POINTER;
}
if (image->user_data != NULL) {
/* free previously attached data */
if (image->user_data_free) {
@ -148,7 +157,7 @@ int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
image->user_data = NULL;
image->user_data_free = NULL;
}
if (data != NULL) {
image->user_data = data;
image->user_data_free = give_up;
@ -275,3 +284,248 @@ int iso_image_get_msg_id(IsoImage *image)
{
return image->id;
}
static
int dir_update_size(IsoImage *image, IsoDir *dir)
{
IsoNode *pos;
pos = dir->children;
while (pos) {
int ret = 1;
if (pos->type == LIBISO_FILE) {
ret = iso_stream_update_size(ISO_FILE(pos)->stream);
} else if (pos->type == LIBISO_DIR) {
/* recurse */
ret = dir_update_size(image, ISO_DIR(pos));
}
if (ret < 0) {
ret = iso_msg_submit(image->id, ret, 0, NULL);
if (ret < 0) {
return ret; /* cancel due error threshold */
}
}
pos = pos->next;
}
return ISO_SUCCESS;
}
int iso_image_update_sizes(IsoImage *image)
{
if (image == NULL) {
return ISO_NULL_POINTER;
}
return dir_update_size(image, image->root);
}
void iso_image_set_ignore_aclea(IsoImage *image, int what)
{
image->builder_ignore_acl = (what & 1);
image->builder_ignore_ea = !!(what & 2);
}
static
int img_register_ino(IsoImage *image, IsoNode *node, int flag)
{
int ret;
ino_t ino;
unsigned int fs_id;
dev_t dev_id;
ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1);
if (ret < 0)
return ret;
if (ret > 0 && ino >= image->used_inodes_start &&
ino <= image->used_inodes_start + (ISO_USED_INODE_RANGE - 1)) {
/* without -1 : rollover hazard on 32 bit */
image->used_inodes[(ino - image->used_inodes_start) / 8]
|= (1 << (ino % 8));
}
return 1;
}
/* Collect the bitmap of used inode numbers in the range of
_ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE
@param flag bit0= recursion is active
*/
int img_collect_inos(IsoImage *image, IsoDir *dir, int flag)
{
int ret, register_dir = 1;
IsoDirIter *iter = NULL;
IsoNode *node;
IsoDir *subdir;
if (dir == NULL)
dir = image->root;
if (image->used_inodes == NULL) {
image->used_inodes = calloc(ISO_USED_INODE_RANGE / 8, 1);
if (image->used_inodes == NULL)
return ISO_OUT_OF_MEM;
} else if(!(flag & 1)) {
memset(image->used_inodes, 0, ISO_USED_INODE_RANGE / 8);
} else {
register_dir = 0;
}
if (register_dir) {
node = (IsoNode *) dir;
ret = img_register_ino(image, node, 0);
if (ret < 0)
return ret;
}
ret = iso_dir_get_children(dir, &iter);
if (ret < 0)
return ret;
while (iso_dir_iter_next(iter, &node) == 1 ) {
ret = img_register_ino(image, node, 0);
if (ret < 0)
goto ex;
if (iso_node_get_type(node) == LIBISO_DIR) {
subdir = (IsoDir *) node;
ret = img_collect_inos(image, subdir, flag | 1);
if (ret < 0)
goto ex;
}
}
ret = 1;
ex:;
if (iter != NULL)
iso_dir_iter_free(iter);
return ret;
}
/**
* A global counter for inode numbers for the ISO image filesystem.
* On image import it gets maxed by the eventual inode numbers from PX
* entries. Up to the first 32 bit rollover it simply increments the counter.
* After the first rollover it uses a look ahead bitmap which gets filled
* by a full tree traversal. It covers the next inode numbers to come
* (somewhere between 1 and ISO_USED_INODE_RANGE which is quite many)
* and advances when being exhausted.
* @param image The image where the number shall be used
* @param flag bit0= reset count (Caution: image must get new inos then)
* @return
* Since ino_t 0 is used as default and considered self-unique,
* the value 0 should only be returned in case of error.
*/
ino_t img_give_ino_number(IsoImage *image, int flag)
{
int ret;
ino_t new_ino, ino_idx;
static uint64_t limit = 0xffffffff;
if (flag & 1) {
image->inode_counter = 0;
if (image->used_inodes != NULL)
free(image->used_inodes);
image->used_inodes = NULL;
image->used_inodes_start = 0;
}
new_ino = image->inode_counter + 1;
if (image->used_inodes == NULL) {
if (new_ino > 0 && new_ino <= limit) {
image->inode_counter = new_ino;
return image->inode_counter;
}
}
/* Look for free number in used territory */
while (1) {
if (new_ino <= 0 || new_ino > limit ||
new_ino >= image->used_inodes_start + ISO_USED_INODE_RANGE ) {
/* Collect a bitmap of used inode numbers ahead */
image->used_inodes_start += ISO_USED_INODE_RANGE;
if (image->used_inodes_start > 0xffffffff ||
image->used_inodes_start <= 0)
image->used_inodes_start = 0;
ret = img_collect_inos(image, NULL, 0);
if (ret < 0)
goto return_result; /* >>> need error return value */
new_ino = image->used_inodes_start + !image->used_inodes_start;
}
ino_idx = (new_ino - image->used_inodes_start) / 8;
if (!(image->used_inodes[ino_idx] & (1 << (new_ino % 8)))) {
image->used_inodes[ino_idx] |= (1 << (new_ino % 8));
break;
}
new_ino++;
}
return_result:;
image->inode_counter = new_ino;
return image->inode_counter;
}
/* @param flag bit0= overwrite any ino, else only ino == 0
bit1= install inode with non-data, non-directory files
bit2= install inode with directories
*/
static
int img_update_ino(IsoImage *image, IsoNode *node, int flag)
{
int ret;
ino_t ino;
unsigned int fs_id;
dev_t dev_id;
ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1);
if (ret < 0)
return ret;
if (ret == 0)
ino = 0;
if (((flag & 1) || ino == 0) &&
(iso_node_get_type(node) == LIBISO_FILE || (flag & (2 | 4))) &&
((flag & 4) || iso_node_get_type(node) != LIBISO_DIR)) {
ret = iso_node_set_unique_id(node, image, 0);
if (ret < 0)
return ret;
}
return 1;
}
/* @param flag bit0= overwrite any ino, else only ino == 0
bit1= install inode with non-data, non-directory files
bit2= install inode with directories
bit3= with bit2: install inode on parameter dir
*/
int img_make_inos(IsoImage *image, IsoDir *dir, int flag)
{
int ret;
IsoDirIter *iter = NULL;
IsoNode *node;
IsoDir *subdir;
if (flag & 8) {
node = (IsoNode *) dir;
ret = img_update_ino(image, node, flag & 7);
if (ret < 0)
goto ex;
}
ret = iso_dir_get_children(dir, &iter);
if (ret < 0)
return ret;
while (iso_dir_iter_next(iter, &node) == 1) {
ret = img_update_ino(image, node, flag & 7);
if (ret < 0)
goto ex;
if (iso_node_get_type(node) == LIBISO_DIR) {
subdir = (IsoDir *) node;
ret = img_make_inos(image, subdir, flag & ~8);
if (ret < 0)
goto ex;
}
}
ret = 1;
ex:;
if (iter != NULL)
iso_dir_iter_free(iter);
return ret;
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
@ -13,6 +14,14 @@
#include "fsource.h"
#include "builder.h"
/* Size of a inode recycling window. Each new window causes a tree traversal.
Window memory consumption is ISO_USED_INODE_RANGE / 8.
This must be a power of 2 smaller than 30 bit and larger than 8 bit.
Here: 32 kB memory for 256k inodes.
*/
#define ISO_USED_INODE_RANGE (1 << 18)
/*
* Image is a context for image manipulation.
* Global objects such as the message_queues must belogn to that
@ -76,6 +85,20 @@ struct Iso_Image
*/
int ignore_special;
/**
* Whether to ignore ACL when inserting nodes into the image.
* Not in effect with loading a complete ISO image but only with image
* manipulation.
*/
unsigned int builder_ignore_acl : 1;
/**
* Whether to ignore EAs when inserting nodes into the image.
* Not in effect with loading a complete ISO image but only with image
* manipulation. ACL does not count as EA.
*/
unsigned int builder_ignore_ea : 1;
/**
* Files to exclude. Wildcard support is included.
*/
@ -107,6 +130,55 @@ struct Iso_Image
*/
void *user_data;
void (*user_data_free)(void *ptr);
/**
* Inode number management. inode_counter is taken over from
* IsoImageFilesystem._ImageFsData after image import.
* It is to be used with img_give_ino_number()
*/
ino_t inode_counter;
/*
* A bitmap of used inode numbers in an interval beginning at
* used_inodes_start and holding ISO_USED_INODE_RANGE bits.
* If a bit is set, then the corresponding inode number is occupied.
* This interval is kept around inode_counter and eventually gets
* advanced by ISO_USED_INODE_RANGE numbers in a tree traversal
* done by img_collect_inos().
*/
uint8_t *used_inodes;
ino_t used_inodes_start;
};
/* Collect the bitmap of used inode numbers in the range of
_ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE
@param flag bit0= recursion is active
*/
int img_collect_inos(IsoImage *image, IsoDir *dir, int flag);
/**
* A global counter for inode numbers for the ISO image filesystem.
* On image import it gets maxed by the eventual inode numbers from PX
* entries. Up to the first 32 bit rollover it simply increments the counter.
* After the first rollover it uses a look ahead bitmap which gets filled
* by a full tree traversal. It covers the next inode numbers to come
* (somewhere between 1 and ISO_USED_INODE_RANGE which is quite many)
* and advances when being exhausted.
* @param image The image where the number shall be used
* @param flag bit0= reset count (Caution: image must get new inos then)
* @return
* Since ino_t 0 is used as default and considered self-unique,
* the value 0 should only be returned in case of error.
*/
ino_t img_give_ino_number(IsoImage *image, int flag);
/* @param flag bit0= overwrite any ino, else only ino == 0
bit1= install inode with non-data, non-directory files
bit2= install inode with directories
bit3= with bit2: install inode on parameter dir
*/
int img_make_inos(IsoImage *image, IsoDir *dir, int flag);
#endif /*LIBISO_IMAGE_H_*/

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -32,7 +32,7 @@ int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
*fname = NULL;
return ISO_SUCCESS;
}
if (!strcmp(t->input_charset, t->output_charset)) {
/* no conversion needed */
name = strdup(str);
@ -50,14 +50,14 @@ int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
name = strdup(str);
}
}
/* ISO 9660:1999 7.5.1 */
if (strlen(name) > 207) {
name[207] = '\0';
}
*fname = name;
return ISO_SUCCESS;
}
@ -117,12 +117,14 @@ int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
IsoFile *file = (IsoFile*) iso;
size = iso_stream_get_size(file->stream);
if (size > (off_t)0xffffffff) {
free(n);
return iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) {
char *ipath = iso_tree_get_node_path(iso);
ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
"File \"%s\" can't be added to image because is "
"greater than 4GB", iso->name);
return 0;
"greater than 4GB", ipath);
free(n);
free(ipath);
return ret;
}
ret = iso_file_src_create(t, file, &src);
@ -159,7 +161,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
/**
* Create the low level ISO 9660:1999 tree from the high level ISO tree.
*
*
* @return
* 1 success, 0 file ignored, < 0 error
*/
@ -185,10 +187,13 @@ int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
max_path = pathlen + 1 + (iso_name ? strlen(iso_name): 0);
if (!t->allow_longer_paths && max_path > 255) {
free(iso_name);
return iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
char *ipath = iso_tree_get_node_path(iso);
ret = iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
"File \"%s\" can't be added to ISO 9660:1999 tree, "
"because its path length is larger than 255", iso->name);
"because its path length is larger than 255", ipath);
free(iso_name);
free(ipath);
return ret;
}
switch (iso->type) {
@ -230,16 +235,19 @@ int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
} else {
/* log and ignore */
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
"El-Torito catalog found on a image without El-Torito.",
iso->name);
"El-Torito catalog found on a image without El-Torito.");
}
break;
case LIBISO_SYMLINK:
case LIBISO_SPECIAL:
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
{
char *ipath = iso_tree_get_node_path(iso);
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
"Can't add %s to ISO 9660:1999 tree. This kind of files "
"can only be added to a Rock Ridget tree. Skipping.",
iso->name);
"can only be added to a Rock Ridget tree. Skipping.",
ipath);
free(ipath);
}
break;
default:
/* should never happen */
@ -269,15 +277,15 @@ cmp_node(const void *f1, const void *f2)
}
/**
* Sort the entries inside an ISO 9660:1999 directory, according to
* ISO 9660:1999, 9.3
* Sort the entries inside an ISO 9660:1999 directory, according to
* ISO 9660:1999, 9.3
*/
static
static
void sort_tree(Iso1999Node *root)
{
size_t i;
qsort(root->info.dir->children, root->info.dir->nchildren,
qsort(root->info.dir->children, root->info.dir->nchildren,
sizeof(void*), cmp_node);
for (i = 0; i < root->info.dir->nchildren; i++) {
Iso1999Node *child = root->info.dir->children[i];
@ -297,9 +305,9 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
nchildren = dir->info.dir->nchildren;
children = dir->info.dir->children;
/* a hash table will temporary hold the names, for fast searching */
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
(compare_function_t)strcmp, &table);
if (ret < 0) {
return ret;
@ -320,7 +328,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
int digits = 1; /* characters to change per name */
/* first, find all child with same name */
while (j + 1 < nchildren &&
while (j + 1 < nchildren &&
!cmp_node(children + i, children + j + 1)) {
++j;
}
@ -330,7 +338,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
}
/*
* A max of 7 characters is good enought, it allows handling up to
* A max of 7 characters is good enought, it allows handling up to
* 9,999,999 files with same name.
*/
while (digits < 8) {
@ -345,7 +353,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
dot = strrchr(full_name, '.');
if (dot != NULL && children[i]->type != ISO1999_DIR) {
/*
/*
* File (not dir) with extension.
*/
int extlen;
@ -358,17 +366,17 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
if (max <= 0) {
/* this can happen if extension is too long */
if (extlen + max > 3) {
/*
/*
* reduce extension len, to give name an extra char
* note that max is negative or 0
* note that max is negative or 0
*/
extlen = extlen + max - 1;
ext[extlen] = '\0';
max = 207 - extlen - 1 - digits;
} else {
/*
/*
* error, we don't support extensions < 3
* This can't happen with current limit of digits.
* This can't happen with current limit of digits.
*/
ret = ISO_ERROR;
goto mangle_cleanup;
@ -428,7 +436,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
children[k]->name = new;
iso_htable_add(table, new, new);
/*
/*
* if we change a name we need to sort again children
* at the end
*/
@ -459,7 +467,7 @@ int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
}
ret = ISO_SUCCESS;
mangle_cleanup : ;
iso_htable_destroy(table, NULL);
return ret;
@ -494,7 +502,7 @@ int iso1999_tree_create(Ecma119Image *t)
{
int ret;
Iso1999Node *root;
if (t == NULL) {
return ISO_NULL_POINTER;
}
@ -507,7 +515,7 @@ int iso1999_tree_create(Ecma119Image *t)
}
return ret;
}
/* the ISO 9660:1999 tree is stored in Ecma119Image target */
t->iso1999_root = root;
@ -549,20 +557,25 @@ size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir)
for (i = 0; i < dir->info.dir->nchildren; ++i) {
size_t remaining;
int section, nsections;
Iso1999Node *child = dir->info.dir->children[i];
size_t dirent_len = calc_dirent_len(t, child);
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
if (dirent_len > remaining) {
/* child directory entry doesn't fit on block */
len += remaining + dirent_len;
} else {
len += dirent_len;
nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
if (dirent_len > remaining) {
/* child directory entry doesn't fit on block */
len += remaining + dirent_len;
} else {
len += dirent_len;
}
}
}
/*
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* (ISO 9660:1999, 6.8.1.3)
*/
len = ROUND_UP(len, BLOCK_SIZE);
@ -626,7 +639,7 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
t = writer->target;
/* compute position of directories */
iso_msg_debug(t->image->id,
iso_msg_debug(t->image->id,
"Computing position of ISO 9660:1999 dir structure");
t->iso1999_ndirs = 0;
calc_dir_pos(t, t->iso1999_root);
@ -647,7 +660,7 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
/**
* Write a single directory record (ISO 9660:1999, 9.1).
*
*
* @param file_id
* if >= 0, we use it instead of the filename (for "." and ".." entries).
* @param len_fi
@ -655,11 +668,12 @@ int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
*/
static
void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
uint8_t *buf, size_t len_fi)
uint8_t *buf, size_t len_fi, int extent)
{
uint32_t len;
uint32_t block;
uint8_t len_dr; /*< size of dir entry */
int multi_extend = 0;
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
: (uint8_t*)node->name;
@ -674,12 +688,13 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
len = node->info.dir->len;
block = node->info.dir->block;
} else if (node->type == ISO1999_FILE) {
len = iso_file_src_get_size(node->info.file);
block = node->info.file->block;
block = node->info.file->sections[extent].block;
len = node->info.file->sections[extent].size;
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
} else {
/*
* for nodes other than files and dirs, we set both
* len and block to 0
/*
* for nodes other than files and dirs, we set both
* len and block to 0
*/
len = 0;
block = 0;
@ -695,20 +710,20 @@ void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
iso_bb(rec->block, block, 4);
iso_bb(rec->length, len, 4);
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
rec->flags[0] = (node->type == ISO1999_DIR) ? 2 : 0;
rec->flags[0] = ((node->type == ISO1999_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
iso_bb(rec->vol_seq_number, 1, 2);
rec->len_fi[0] = len_fi;
}
/**
* Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
* Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
*/
static
int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
{
IsoImage *image;
Ecma119Image *t;
/* The enhanced volume descriptor is like the sup vol desc */
struct ecma119_sup_vol_desc vol;
@ -741,7 +756,7 @@ int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
vol.vol_desc_type[0] = 2;
memcpy(vol.std_identifier, "CD001", 5);
/* descriptor version is 2 (ISO/IEC 9660:1999, 8.5.2) */
vol.vol_desc_version[0] = 2;
strncpy_pad((char*)vol.volume_id, vol_id, 32);
@ -754,12 +769,12 @@ int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
iso_lsb(vol.l_path_table_pos, t->iso1999_l_path_table_pos, 4);
iso_msb(vol.m_path_table_pos, t->iso1999_m_path_table_pos, 4);
write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1);
write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1, 0);
strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
strncpy_pad((char*)vol.publisher_id, pub_id, 128);
strncpy_pad((char*)vol.data_prep_id, data_id, 128);
strncpy_pad((char*)vol.system_id, system_id, 32);
strncpy_pad((char*)vol.application_id, application_id, 128);
@ -801,30 +816,34 @@ int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
memset(buffer, 0, BLOCK_SIZE);
/* write the "." and ".." entries first */
write_one_dir_record(t, dir, 0, buf, 1);
write_one_dir_record(t, dir, 0, buf, 1, 0);
buf += 34;
write_one_dir_record(t, dir, 1, buf, 1);
write_one_dir_record(t, dir, 1, buf, 1, 0);
buf += 34;
for (i = 0; i < dir->info.dir->nchildren; i++) {
int section, nsections;
Iso1999Node *child = dir->info.dir->children[i];
/* compute len of directory entry */
fi_len = strlen(child->name);
len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
if ( (buf + len - buffer) > BLOCK_SIZE) {
/* dir doesn't fit in current block */
ret = iso_write(t, buffer, BLOCK_SIZE);
if (ret < 0) {
return ret;
nsections = (child->type == ISO1999_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
if ( (buf + len - buffer) > BLOCK_SIZE) {
/* dir doesn't fit in current block */
ret = iso_write(t, buffer, BLOCK_SIZE);
if (ret < 0) {
return ret;
}
memset(buffer, 0, BLOCK_SIZE);
buf = buffer;
}
memset(buffer, 0, BLOCK_SIZE);
buf = buffer;
/* write the directory entry in any case */
write_one_dir_record(t, child, -1, buf, fi_len, section);
buf += len;
}
/* write the directory entry in any case */
write_one_dir_record(t, child, -1, buf, fi_len);
buf += len;
}
/* write the last block */
@ -1000,7 +1019,7 @@ int iso1999_writer_create(Ecma119Image *target)
writer->data = NULL;
writer->target = target;
iso_msg_debug(target->image->id,
iso_msg_debug(target->image->id,
"Creating low level ISO 9660:1999 tree...");
ret = iso1999_tree_create(target);
if (ret < 0) {

View File

@ -1,9 +1,9 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2007 Mario Danic
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -13,6 +13,8 @@
#include "image.h"
#include "filesrc.h"
#include "eltorito.h"
#include "libisofs.h"
#include <stdlib.h>
#include <stdio.h>
@ -47,7 +49,7 @@ int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name)
*name = jname;
return ISO_SUCCESS;
} else {
/*
/*
* only possible if mem error, as check for empty names is done
* in public tree
*/
@ -111,11 +113,14 @@ int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
IsoFile *file = (IsoFile*) iso;
size = iso_stream_get_size(file->stream);
if (size > (off_t)0xffffffff) {
if (size > (off_t)MAX_ISO_FILE_SECTION_SIZE && t->iso_level != 3) {
char *ipath = iso_tree_get_node_path(iso);
free(joliet);
return iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
ret = iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
"File \"%s\" can't be added to image because is "
"greater than 4GB", iso->name);
"greater than 4GB", ipath);
free(ipath);
return ret;
}
ret = iso_file_src_create(t, file, &src);
@ -152,7 +157,7 @@ int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
/**
* Create the low level Joliet tree from the high level ISO tree.
*
*
* @return
* 1 success, 0 file ignored, < 0 error
*/
@ -177,14 +182,17 @@ int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen)
}
max_path = pathlen + 1 + (jname ? ucslen(jname) * 2 : 0);
if (!t->joliet_longer_paths && max_path > 240) {
free(jname);
char *ipath = iso_tree_get_node_path(iso);
/*
* Wow!! Joliet is even more restrictive than plain ISO-9660,
* that allows up to 255 bytes!!
*/
return iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
ret = iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
"File \"%s\" can't be added to Joliet tree, because "
"its path length is larger than 240", iso->name);
"its path length is larger than 240", ipath);
free(jname);
free(ipath);
return ret;
}
switch (iso->type) {
@ -226,15 +234,19 @@ int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen)
} else {
/* log and ignore */
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
"El-Torito catalog found on a image without El-Torito.",
iso->name);
"El-Torito catalog found on a image without El-Torito.");
}
break;
case LIBISO_SYMLINK:
case LIBISO_SPECIAL:
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
"Can't add %s to Joliet tree. This kind of files can only"
" be added to a Rock Ridget tree. Skipping.", iso->name);
{
char *ipath = iso_tree_get_node_path(iso);
ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
"Can't add %s to Joliet tree. %s can only be added to a "
"Rock Ridget tree.", ipath, (iso->type == LIBISO_SYMLINK ?
"Symlinks" : "Special files"));
free(ipath);
}
break;
default:
/* should never happen */
@ -257,12 +269,12 @@ cmp_node(const void *f1, const void *f2)
return ucscmp(f->name, g->name);
}
static
static
void sort_tree(JolietNode *root)
{
size_t i;
qsort(root->info.dir->children, root->info.dir->nchildren,
qsort(root->info.dir->children, root->info.dir->nchildren,
sizeof(void*), cmp_node);
for (i = 0; i < root->info.dir->nchildren; i++) {
JolietNode *child = root->info.dir->children[i];
@ -286,24 +298,25 @@ int joliet_create_mangled_name(uint16_t *dest, uint16_t *src, int digits,
int ret, pos;
uint16_t *ucsnumber;
char fmt[16];
char *nstr = alloca(digits + 1);
char nstr[72]; /* The only caller of this function allocates dest with 66
elements and limits digits to < 8 */
sprintf(fmt, "%%0%dd", digits);
sprintf(nstr, fmt, number);
ret = str2ucs("ASCII", nstr, &ucsnumber);
if (ret < 0) {
return ret;
}
/* copy name */
pos = ucslen(src);
ucsncpy(dest, src, pos);
/* copy number */
ucsncpy(dest + pos, ucsnumber, digits);
pos += digits;
if (ext[0] != (uint16_t)0) {
size_t extlen = ucslen(ext);
dest[pos++] = (uint16_t)0x2E00; /* '.' in big endian UCS */
@ -326,9 +339,9 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
nchildren = dir->info.dir->nchildren;
children = dir->info.dir->children;
/* a hash table will temporary hold the names, for fast searching */
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
(compare_function_t)ucscmp, &table);
if (ret < 0) {
return ret;
@ -349,7 +362,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
int digits = 1; /* characters to change per name */
/* first, find all child with same name */
while (j + 1 < nchildren &&
while (j + 1 < nchildren &&
!cmp_node_name(children + i, children + j + 1)) {
++j;
}
@ -359,9 +372,11 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
}
/*
* A max of 7 characters is good enought, it allows handling up to
* A max of 7 characters is good enought, it allows handling up to
* 9,999,999 files with same name.
*/
/* Important: joliet_create_mangled_name() relies on digits < 72 */
while (digits < 8) {
int ok, k;
uint16_t *dot;
@ -374,7 +389,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
dot = ucsrchr(full_name, '.');
if (dot != NULL && children[i]->type != JOLIET_DIR) {
/*
/*
* File (not dir) with extension
*/
int extlen;
@ -387,17 +402,17 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
if (max <= 0) {
/* this can happen if extension is too long */
if (extlen + max > 3) {
/*
/*
* reduce extension len, to give name an extra char
* note that max is negative or 0
* note that max is negative or 0
*/
extlen = extlen + max - 1;
ext[extlen] = 0;
max = 66 - extlen - 1 - digits;
} else {
/*
/*
* error, we don't support extensions < 3
* This can't happen with current limit of digits.
* This can't happen with current limit of digits.
*/
ret = ISO_ERROR;
goto mangle_cleanup;
@ -455,7 +470,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
children[k]->name = new;
iso_htable_add(table, new, new);
/*
/*
* if we change a name we need to sort again children
* at the end
*/
@ -486,7 +501,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
}
ret = ISO_SUCCESS;
mangle_cleanup : ;
iso_htable_destroy(table, NULL);
return ret;
@ -521,7 +536,7 @@ int joliet_tree_create(Ecma119Image *t)
{
int ret;
JolietNode *root;
if (t == NULL) {
return ISO_NULL_POINTER;
}
@ -534,7 +549,7 @@ int joliet_tree_create(Ecma119Image *t)
}
return ret;
}
/* the Joliet tree is stored in Ecma119Image target */
t->joliet_root = root;
@ -580,20 +595,25 @@ size_t calc_dir_size(Ecma119Image *t, JolietNode *dir)
for (i = 0; i < dir->info.dir->nchildren; ++i) {
size_t remaining;
int section, nsections;
JolietNode *child = dir->info.dir->children[i];
size_t dirent_len = calc_dirent_len(t, child);
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
if (dirent_len > remaining) {
/* child directory entry doesn't fit on block */
len += remaining + dirent_len;
} else {
len += dirent_len;
nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
if (dirent_len > remaining) {
/* child directory entry doesn't fit on block */
len += remaining + dirent_len;
} else {
len += dirent_len;
}
}
}
/*
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* The size of a dir is always a multiple of block size, as we must add
* the size of the unused space after the last directory record
* (ECMA-119, 6.8.1.3)
*/
len = ROUND_UP(len, BLOCK_SIZE);
@ -677,7 +697,7 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
/**
* Write a single directory record for Joliet. It is like (ECMA-119, 9.1),
* but file identifier is stored in UCS.
*
*
* @param file_id
* if >= 0, we use it instead of the filename (for "." and ".." entries).
* @param len_fi
@ -686,11 +706,12 @@ int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
*/
static
void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
uint8_t *buf, size_t len_fi)
uint8_t *buf, size_t len_fi, int extent)
{
uint32_t len;
uint32_t block;
uint8_t len_dr; /*< size of dir entry */
int multi_extend = 0;
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
: (uint8_t*)node->name;
@ -713,12 +734,13 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
len = node->info.dir->len;
block = node->info.dir->block;
} else if (node->type == JOLIET_FILE) {
len = iso_file_src_get_size(node->info.file);
block = node->info.file->block;
block = node->info.file->sections[extent].block;
len = node->info.file->sections[extent].size;
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
} else {
/*
* for nodes other than files and dirs, we set both
* len and block to 0
/*
* for nodes other than files and dirs, we set both
* len and block to 0
*/
len = 0;
block = 0;
@ -734,7 +756,7 @@ void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
iso_bb(rec->block, block, 4);
iso_bb(rec->length, len, 4);
iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
rec->flags[0] = (node->type == JOLIET_DIR) ? 2 : 0;
rec->flags[0] = ((node->type == JOLIET_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
iso_bb(rec->vol_seq_number, 1, 2);
rec->len_fi[0] = len_fi;
}
@ -748,19 +770,19 @@ void ucsncpy_pad(uint16_t *dest, const uint16_t *src, size_t max)
{
char *cdest, *csrc;
size_t len, i;
cdest = (char*)dest;
csrc = (char*)src;
if (src != NULL) {
len = MIN(ucslen(src) * 2, max);
} else {
len = 0;
}
for (i = 0; i < len; ++i)
cdest[i] = csrc[i];
for (i = len; i < max; i += 2) {
cdest[i] = '\0';
cdest[i + 1] = ' ';
@ -805,7 +827,7 @@ int joliet_writer_write_vol_desc(IsoImageWriter *writer)
memcpy(vol.std_identifier, "CD001", 5);
vol.vol_desc_version[0] = 1;
ucsncpy_pad((uint16_t*)vol.volume_id, vol_id, 32);
/* make use of UCS-2 Level 3 */
memcpy(vol.esc_sequences, "%/E", 3);
@ -817,12 +839,12 @@ int joliet_writer_write_vol_desc(IsoImageWriter *writer)
iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4);
iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4);
write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1);
write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1, 0);
ucsncpy_pad((uint16_t*)vol.vol_set_id, volset_id, 128);
ucsncpy_pad((uint16_t*)vol.publisher_id, pub_id, 128);
ucsncpy_pad((uint16_t*)vol.data_prep_id, data_id, 128);
ucsncpy_pad((uint16_t*)vol.system_id, system_id, 32);
ucsncpy_pad((uint16_t*)vol.application_id, application_id, 128);
@ -864,12 +886,13 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir)
memset(buffer, 0, BLOCK_SIZE);
/* write the "." and ".." entries first */
write_one_dir_record(t, dir, 0, buf, 1);
write_one_dir_record(t, dir, 0, buf, 1, 0);
buf += 34;
write_one_dir_record(t, dir, 1, buf, 1);
write_one_dir_record(t, dir, 1, buf, 1, 0);
buf += 34;
for (i = 0; i < dir->info.dir->nchildren; i++) {
int section, nsections;
JolietNode *child = dir->info.dir->children[i];
/* compute len of directory entry */
@ -879,18 +902,23 @@ int write_one_dir(Ecma119Image *t, JolietNode *dir)
len += 4;
}
if ( (buf + len - buffer) > BLOCK_SIZE) {
/* dir doesn't fit in current block */
ret = iso_write(t, buffer, BLOCK_SIZE);
if (ret < 0) {
return ret;
nsections = (child->type == JOLIET_FILE) ? child->info.file->nsections : 1;
for (section = 0; section < nsections; ++section) {
if ( (buf + len - buffer) > BLOCK_SIZE) {
/* dir doesn't fit in current block */
ret = iso_write(t, buffer, BLOCK_SIZE);
if (ret < 0) {
return ret;
}
memset(buffer, 0, BLOCK_SIZE);
buf = buffer;
}
memset(buffer, 0, BLOCK_SIZE);
buf = buffer;
/* write the directory entry in any case */
write_one_dir_record(t, child, -1, buf, fi_len, section);
buf += len;
}
/* write the directory entry in any case */
write_one_dir_record(t, child, -1, buf, fi_len);
buf += len;
}
/* write the last block */

View File

@ -1,5 +1,5 @@
/* libiso_msgs (generated from libdax_msgs : Qua Fev 13 14:58:12 CET 2008)
/* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
Message handling facility of libisofs.
Copyright (C) 2006 - 2008 Thomas Schmitt <scdbackup@gmx.net>,
provided under GPL version 2
@ -268,10 +268,12 @@ int libiso_msgs__text_to_sev(char *severity_name, int *severity,
*severity= LIBISO_MSGS_SEV_UPDATE;
else if(strncmp(severity_name,"DEBUG",5)==0)
*severity= LIBISO_MSGS_SEV_DEBUG;
else if(strncmp(severity_name,"ERRFILE",7)==0)
*severity= LIBISO_MSGS_SEV_ERRFILE;
else if(strncmp(severity_name,"ALL",3)==0)
*severity= LIBISO_MSGS_SEV_ALL;
else {
*severity= LIBISO_MSGS_SEV_NEVER;
*severity= LIBISO_MSGS_SEV_ALL;
return(0);
}
return(1);
@ -282,7 +284,7 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
int flag)
{
if(flag&1) {
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
return(1);
}
*severity_name= "";
@ -308,6 +310,8 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
*severity_name= "UPDATE";
else if(severity>=LIBISO_MSGS_SEV_DEBUG)
*severity_name= "DEBUG";
else if(severity>=LIBISO_MSGS_SEV_ERRFILE)
*severity_name= "ERRFILE";
else if(severity>=LIBISO_MSGS_SEV_ALL)
*severity_name= "ALL";
else {

View File

@ -1,5 +1,5 @@
/* libiso_msgs (generated from libdax_msgs : Qua Fev 13 14:58:12 CET 2008)
/* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
Message handling facility of libisofs.
Copyright (C) 2006-2008 Thomas Schmitt <scdbackup@gmx.net>,
provided under GPL version 2
@ -120,6 +120,19 @@ struct libiso_msgs_item;
*/
#define LIBISO_MSGS_SEV_ALL 0x00000000
/** Messages of this severity shall transport plain disk file paths
whenever an event of severity SORRY or above is related with an
individual disk file.
No message text shall be added to the file path. The ERRFILE message
shall be issued before the human readable message which carries the
true event severity. That message should contain the file path so it
can be found by strstr(message, path)!=NULL.
The error code shall be the same as with the human readable message.
*/
#define LIBISO_MSGS_SEV_ERRFILE 0x08000000
/** Debugging messages not to be visible to normal users by default
*/
#define LIBISO_MSGS_SEV_DEBUG 0x10000000
@ -149,7 +162,7 @@ struct libiso_msgs_item;
like ISO image generation. A precondition for such a severity ease is
that the action can be continued after the incident.
See below MISHAP for what xorriso would need instead of this kind of SORRY
an generates for itself in case of libisofs image generation.
and generates for itself in case of libisofs image generation.
E.g.: A pattern yields no result.
A speed setting cannot be made.
@ -610,6 +623,7 @@ Range "application" : 0x00040000 to 0x0004ffff
0x00040005 (NOTE,HIGH) : Application supplied message
0x00040006 (UPDATE,HIGH) : Application supplied message
0x00040007 (DEBUG,HIGH) : Application supplied message
0x00040008 (*,HIGH) : Application supplied message
------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
#include <ctype.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/* for gettimeofday() */
#include <sys/time.h>
/* This code stems from syslinux-3.72/utils/isohybrid, a perl script
under GPL which is Copyright 2002-2008 H. Peter Anvin.
Line numbers in comments refer to the lines of that script.
It has been analyzed and re-written in C language 2008 by Thomas Schmitt,
and is now under the licenses to which H.Peter Anvin agreed:
http://syslinux.zytor.com/archives/2008-November/011105.html
Date: Mon, 10 Nov 2008 08:36:46 -0800
From: H. Peter Anvin <hpa@zytor.com>
I hereby give permission for this code, translated to the C language, to
be released under either the LGPL or the MIT/ISC/2-clause BSD licenses
or both, at your option.
Sincerely, H. Peter Anvin
In the context of libisofs this code derives its matching open source
license from above stem licenses, typically from LGPL.
In case its generosity is needed, here is the 2-clause BSD license:
make_isohybrid_mbr.c is copyright 2002-2008 H. Peter Anvin
and 2008 libburnia project.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE PROVIDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* A helper function. One could replace it by one or two macros. */
static int lsb_to_buf(char **wpt, int value, int bits, int flag)
{
int b;
for (b = 0; b < bits; b += 8)
*((unsigned char *) ((*wpt)++)) = (value >> b) & 0xff;
return (1);
}
/*
* Create a MBR for an isohybrid enabled ISOLINUX boot image.
*
* It is assumed that the caller has verified the readiness of the boot image
* by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
*
* @param bin_lba The predicted LBA of isolinux.bin within the emerging ISO.
* @param img_blocks The predicted number of 2048 byte blocks in the ISO.
* It will get rounded up to full MBs and that many blocks
* must really be written as ISO 9660 image.
* @param mbr A buffer of at least 512 bytes to take the result which is
* to be written as the very beginning of the ISO.
* @param flag unused yet, submit 0
* @return <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
*/
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag)
{
/* According to H. Peter Anvin this binary code stems from
syslinux-3.72/mbr/isohdpfx.S
*/
static int mbr_code_size = 271;
static unsigned char mbr_code[271] = { 0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e,
0xd0, 0xbc, 0x00, 0x7c, 0x89, 0xe6, 0x06, 0x57, 0x52, 0x8e, 0xc0,
0xfb, 0xfc, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5, 0xea,
0x20, 0x06, 0x00, 0x00, 0x52, 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0x31,
0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72, 0x14, 0x81, 0xfb, 0x55,
0xaa, 0x75, 0x0e, 0x83, 0xe1, 0x01, 0x74, 0x09, 0x66, 0xc7, 0x06,
0xb4, 0x06, 0xb4, 0x42, 0xeb, 0x15, 0x5a, 0x51, 0xb4, 0x08, 0xcd,
0x13, 0x83, 0xe1, 0x3f, 0x51, 0x0f, 0xb6, 0xc6,
0x40, 0x50, 0xf7, 0xe1, 0x52, 0x50, 0xbb, 0x00, 0x7c, 0xb9, 0x04,
0x00, 0x66, 0xa1, 0xb0, 0x07, 0xe8, 0x40, 0x00, 0x72, 0x74, 0x66,
0x40, 0x80, 0xc7, 0x02, 0xe2, 0xf4, 0x66, 0x81, 0x3e, 0x40, 0x7c,
0xfb, 0xc0, 0x78, 0x70, 0x75, 0x07, 0xfa, 0xbc, 0xf4, 0x7b, 0xe9,
0xc6, 0x75, 0xe8, 0x79, 0x00, 0x69, 0x73, 0x6f, 0x6c, 0x69, 0x6e,
0x75, 0x78, 0x2e, 0x62, 0x69, 0x6e, 0x20, 0x6d, 0x69, 0x73, 0x73,
0x69, 0x6e, 0x67, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x72,
0x75, 0x70, 0x74,
0x2e, 0x0d, 0x0a, 0x66, 0x60, 0x66, 0x31, 0xd2, 0x66, 0x52, 0x66,
0x50, 0x06, 0x53, 0x6a, 0x01, 0x6a, 0x10, 0x89, 0xe6, 0x66, 0xf7,
0x36, 0xf0, 0x7b, 0xc0, 0xe4, 0x06, 0x88, 0xe1, 0x88, 0xc5, 0x92,
0xf6, 0x36, 0xf6, 0x7b, 0x88, 0xc6, 0x08, 0xe1, 0x41, 0xb8, 0x01,
0x02, 0x8a, 0x16, 0xfa, 0x7b, 0xcd, 0x13, 0x8d, 0x64, 0x10, 0x66,
0x61, 0xc3, 0xe8, 0x1e, 0x00, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
0x6c, 0x6f, 0x61,
0x64, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x0d, 0x0a, 0x5e,
0xac, 0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07, 0xcd, 0x10,
0x3c, 0x0a, 0x75, 0xf1, 0xcd, 0x18, 0xf4, 0xeb, 0xfd };
static int h = 64, s = 32;
int i, warn_size = 0, id;
char *wpt;
off_t imgsize, cylsize, frac, padding, c, cc;
/* For generating a weak random number */
struct timeval tv;
struct timezone tz;
if (bin_lba < 0 || bin_lba >= (1 << 29))
return (0); /* 1 TB limit of signed 32 bit addressing of 512 byte blocks */
/*
84: Gets size of image in bytes.
89:
*/
imgsize = ((off_t) *img_blocks) * (off_t) 2048;
/*
90: Computes $padding, size of padded image and number $c of
pseudo-cylinders ($h and $s are constants set in line 24).
102: $cc is $c curbed to 1024.
*/
cylsize = h * s * 512;
frac = imgsize % cylsize;
padding = (frac > 0 ? cylsize - frac : 0);
imgsize += padding;
*img_blocks = imgsize / (off_t) 2048;
c = imgsize / cylsize;
if (c > 1024) {
warn_size = 1;
cc = 1024;
} else
cc = c;
/*
107: Brings the hex-encoded bytes from the file __END__ into
113: the MBR buffer. (This function holds them in mbr_code[].)
*/
for (i = 0; i < mbr_code_size; i++)
mbr[i] = mbr_code[i];
/*
118: Pads up to 432
*/
for (i = mbr_code_size; i < 432; i++)
mbr[i] = 0;
/* From here on use write cursor wpt */
wpt = mbr + 432;
/*
120: Converts LBA of isolinux.bin to blocksize 512 and writes
to buffer. Appends 4 zero bytes.
*/
lsb_to_buf(&wpt, bin_lba * 4, 32, 0);
lsb_to_buf(&wpt, 0, 32, 0);
/*
121: I do not understand where $id should eventually come
from. An environment variable ?
125: Whatever, i use some 32-bit random value with no crypto strength.
*/
gettimeofday(&tv, &tz);
id = 0xffffffff & (tv.tv_sec ^ (tv.tv_usec * 2000));
/*
126: Adds 4 id bytes and 2 zero bytes.
*/
lsb_to_buf(&wpt, id, 32, 0);
lsb_to_buf(&wpt, 0, 16, 0);
/*
129: Composes 16 byte record from the parameters determined
147: so far. Appends it to buffer and add 48 zero bytes.
*/
/* There are 4 "partition slots". Only the first is non-zero here.
In the perl script, the fields are set in variables and then
written to buffer. I omit the variables.
*/
/* 0x80 */
lsb_to_buf(&wpt, 0x80, 8, 0);
/* bhead */
lsb_to_buf(&wpt, 0, 8, 0);
/* bsect */
lsb_to_buf(&wpt, 1, 8, 0);
/* bcyl */
lsb_to_buf(&wpt, 0, 8, 0);
/* fstype */
lsb_to_buf(&wpt, 0x83, 8, 0);
/* ehead */
lsb_to_buf(&wpt, h - 1, 8, 0);
/* esect */
lsb_to_buf(&wpt, s + (((cc - 1) & 0x300) >> 2), 8, 0);
/* ecyl */
lsb_to_buf(&wpt, (cc - 1) & 0xff, 8, 0);
/* 0 */
lsb_to_buf(&wpt, 0, 32, 0);
/* psize */
lsb_to_buf(&wpt, c * h * s, 32, 0);
/* Fill the other three slots with zeros */
for (i = 0; i < 3 * 4; i++)
lsb_to_buf(&wpt, 0, 32, 0);
/*
148: Appends bytes 0x55 , 0xAA.
*/
lsb_to_buf(&wpt, 0x55, 8, 0);
lsb_to_buf(&wpt, 0xaa, 8, 0);
return (1);
}

View File

@ -1,11 +1,12 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include <stdlib.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
@ -14,9 +15,12 @@
#include "libisofs.h"
#include "messages.h"
/*
#include "util.h"
/*
* error codes are 32 bit numbers, that follow the following conventions:
*
*
* bit 31 (MSB) -> 1 (to make the value always negative)
* bits 30-24 -> Encoded severity (Use ISO_ERR_SEV to translate an error code
* to a LIBISO_MSGS_SEV_* constant)
@ -40,7 +44,7 @@
* bits 15-0 -> Error code
*/
#define ISO_ERR_SEV(e) (e & 0x7F000000)
#define ISO_ERR_PRIO(e) ((e & 0x00F00000) << 8)
#define ISO_ERR_PRIO(e) ((e & 0x00700000) << 8)
#define ISO_ERR_CODE(e) ((e & 0x0000FFFF) | 0x00030000)
int iso_message_id = LIBISO_MSGS_ORIGIN_IMAGE_BASE;
@ -54,8 +58,16 @@ int abort_threshold = LIBISO_MSGS_SEV_FAILURE;
struct libiso_msgs *libiso_msgr = NULL;
int iso_init()
/*
@param flag bit0= do not set up locale by LC_* environment variables
*/
int iso_init_with_flag(int flag)
{
if (! (flag & 1)) {
iso_init_locale(0);
}
if (libiso_msgr == NULL) {
if (libiso_msgs_new(&libiso_msgr, 0) <= 0)
return ISO_FATAL_ERROR;
@ -65,6 +77,12 @@ int iso_init()
return 1;
}
int iso_init()
{
return iso_init_with_flag(0);
}
void iso_finish()
{
libiso_msgs_destroy(&libiso_msgr, 0);
@ -77,7 +95,7 @@ int iso_set_abort_severity(char *severity)
ret = libiso_msgs__text_to_sev(severity, &sevno, 0);
if (ret <= 0)
return ISO_WRONG_ARG_VALUE;
if (sevno > LIBISO_MSGS_SEV_FAILURE || sevno < LIBISO_MSGS_SEV_NOTE)
if (sevno > LIBISO_MSGS_SEV_FAILURE || sevno < LIBISO_MSGS_SEV_NOTE)
return ISO_WRONG_ARG_VALUE;
ret = abort_threshold;
abort_threshold = sevno;
@ -100,110 +118,148 @@ void iso_msg_debug(int imgid, const char *fmt, ...)
const char *iso_error_to_msg(int errcode)
{
switch(errcode) {
case ISO_CANCELED:
case ISO_CANCELED:
return "Operation canceled";
case ISO_FATAL_ERROR:
case ISO_FATAL_ERROR:
return "Unknown or unexpected fatal error";
case ISO_ERROR:
case ISO_ERROR:
return "Unknown or unexpected error";
case ISO_ASSERT_FAILURE:
case ISO_ASSERT_FAILURE:
return "Internal programming error. Please report this bug";
case ISO_NULL_POINTER:
return "NULL pointer as value for an arg. that doesn't allow NULL";
case ISO_OUT_OF_MEM:
case ISO_NULL_POINTER:
return "NULL pointer as value for an arg. that does not allow NULL";
case ISO_OUT_OF_MEM:
return "Memory allocation error";
case ISO_INTERRUPTED:
case ISO_INTERRUPTED:
return "Interrupted by a signal";
case ISO_WRONG_ARG_VALUE:
case ISO_WRONG_ARG_VALUE:
return "Invalid parameter value";
case ISO_THREAD_ERROR:
return "Can't create a needed thread";
case ISO_WRITE_ERROR:
case ISO_THREAD_ERROR:
return "Cannot create a needed thread";
case ISO_WRITE_ERROR:
return "Write error";
case ISO_BUF_READ_ERROR:
case ISO_BUF_READ_ERROR:
return "Buffer read error";
case ISO_NODE_ALREADY_ADDED:
case ISO_NODE_ALREADY_ADDED:
return "Trying to add to a dir a node already added to a dir";
case ISO_NODE_NAME_NOT_UNIQUE:
case ISO_NODE_NAME_NOT_UNIQUE:
return "Node with same name already exists";
case ISO_NODE_NOT_ADDED_TO_DIR:
case ISO_NODE_NOT_ADDED_TO_DIR:
return "Trying to remove a node that was not added to dir";
case ISO_NODE_DOESNT_EXIST:
case ISO_NODE_DOESNT_EXIST:
return "A requested node does not exist";
case ISO_IMAGE_ALREADY_BOOTABLE:
case ISO_IMAGE_ALREADY_BOOTABLE:
return "Try to set the boot image of an already bootable image";
case ISO_BOOT_IMAGE_NOT_VALID:
case ISO_BOOT_IMAGE_NOT_VALID:
return "Trying to use an invalid file as boot image";
case ISO_FILE_ERROR:
case ISO_FILE_ERROR:
return "Error on file operation";
case ISO_FILE_ALREADY_OPENNED:
return "Trying to open an already openned file";
case ISO_FILE_ACCESS_DENIED:
case ISO_FILE_ALREADY_OPENED:
return "Trying to open an already opened file";
case ISO_FILE_ACCESS_DENIED:
return "Access to file is not allowed";
case ISO_FILE_BAD_PATH:
case ISO_FILE_BAD_PATH:
return "Incorrect path to file";
case ISO_FILE_DOESNT_EXIST:
case ISO_FILE_DOESNT_EXIST:
return "The file does not exist in the filesystem";
case ISO_FILE_NOT_OPENNED:
return "Trying to read or close a file not openned";
case ISO_FILE_IS_DIR:
case ISO_FILE_NOT_OPENED:
return "Trying to read or close a file not opened";
case ISO_FILE_IS_DIR:
return "Directory used where no dir is expected";
case ISO_FILE_READ_ERROR:
case ISO_FILE_READ_ERROR:
return "Read error";
case ISO_FILE_IS_NOT_DIR:
case ISO_FILE_IS_NOT_DIR:
return "Not dir used where a dir is expected";
case ISO_FILE_IS_NOT_SYMLINK:
case ISO_FILE_IS_NOT_SYMLINK:
return "Not symlink used where a symlink is expected";
case ISO_FILE_SEEK_ERROR:
return "Can't seek to specified location";
case ISO_FILE_IGNORED:
case ISO_FILE_SEEK_ERROR:
return "Cannot seek to specified location";
case ISO_FILE_IGNORED:
return "File not supported in ECMA-119 tree and thus ignored";
case ISO_FILE_TOO_BIG:
case ISO_FILE_TOO_BIG:
return "A file is bigger than supported by used standard";
case ISO_FILE_CANT_WRITE:
case ISO_FILE_CANT_WRITE:
return "File read error during image creation";
case ISO_FILENAME_WRONG_CHARSET:
return "Can't convert filename to requested charset";
case ISO_FILE_CANT_ADD:
return "File can't be added to the tree";
case ISO_FILE_IMGPATH_WRONG:
case ISO_FILENAME_WRONG_CHARSET:
case ISO_FILENAME_WRONG_CHARSET_OLD:
return "Cannot convert filename to requested charset";
case ISO_FILE_CANT_ADD:
return "File cannot be added to the tree";
case ISO_FILE_IMGPATH_WRONG:
return "File path break specification constraints and will be ignored";
case ISO_CHARSET_CONV_ERROR:
case ISO_CHARSET_CONV_ERROR:
return "Charset conversion error";
case ISO_MANGLE_TOO_MUCH_FILES:
return "Too much files to mangle, can't guarantee unique file names";
case ISO_WRONG_PVD:
case ISO_MANGLE_TOO_MUCH_FILES:
return "Too much files to mangle, cannot guarantee unique file names";
case ISO_WRONG_PVD:
return "Wrong or damaged Primary Volume Descriptor";
case ISO_WRONG_RR:
case ISO_WRONG_RR:
return "Wrong or damaged RR entry";
case ISO_UNSUPPORTED_RR:
case ISO_UNSUPPORTED_RR:
return "Unsupported RR feature";
case ISO_WRONG_ECMA119:
case ISO_WRONG_ECMA119:
return "Wrong or damaged ECMA-119";
case ISO_UNSUPPORTED_ECMA119:
case ISO_UNSUPPORTED_ECMA119:
return "Unsupported ECMA-119 feature";
case ISO_WRONG_EL_TORITO:
case ISO_WRONG_EL_TORITO:
return "Wrong or damaged El-Torito catalog";
case ISO_UNSUPPORTED_EL_TORITO:
case ISO_UNSUPPORTED_EL_TORITO:
return "Unsupported El-Torito feature";
case ISO_ISOLINUX_CANT_PATCH:
return "Can't patch isolinux boot image";
case ISO_UNSUPPORTED_SUSP:
case ISO_ISOLINUX_CANT_PATCH:
return "Cannot patch isolinux boot image";
case ISO_UNSUPPORTED_SUSP:
return "Unsupported SUSP feature";
case ISO_WRONG_RR_WARN:
case ISO_WRONG_RR_WARN:
return "Error on a RR entry that can be ignored";
case ISO_SUSP_UNHANDLED:
case ISO_SUSP_UNHANDLED:
return "Error on a RR entry that can be ignored";
case ISO_SUSP_MULTIPLE_ER:
case ISO_SUSP_MULTIPLE_ER:
return "Multiple ER SUSP entries found";
case ISO_UNSUPPORTED_VD:
case ISO_UNSUPPORTED_VD:
return "Unsupported volume descriptor found";
case ISO_EL_TORITO_WARN:
case ISO_EL_TORITO_WARN:
return "El-Torito related warning";
case ISO_IMAGE_WRITE_CANCELED:
case ISO_IMAGE_WRITE_CANCELED:
return "Image write cancelled";
case ISO_EL_TORITO_HIDDEN:
case ISO_EL_TORITO_HIDDEN:
return "El-Torito image is hidden";
case ISO_DATA_SOURCE_SORRY:
case ISO_DATA_SOURCE_MISHAP:
case ISO_DATA_SOURCE_FAILURE:
case ISO_DATA_SOURCE_FATAL:
return "Read error occured with IsoDataSource";
case ISO_AAIP_IGNORED:
return "AAIP info with ACL or xattr in ISO image will be ignored";
case ISO_AAIP_BAD_ACL:
return "Error with decoding ACL from AAIP info";
case ISO_AAIP_BAD_ACL_TEXT:
return "Error with encoding ACL for AAIP";
case ISO_AAIP_NOT_ENABLED:
return "AAIP processing for ACL or xattr not enabled at compile time";
case ISO_AAIP_BAD_AASTRING:
return "Error with decoding AAIP info for ACL or xattr";
case ISO_AAIP_NO_GET_LOCAL:
return "Error with reading ACL or xattr from local file";
case ISO_AAIP_NO_SET_LOCAL:
return "Error with attaching ACL or xattr to local file";
case ISO_AAIP_NON_USER_NAME:
return "Unallowed attempt to set an xattr with non-userspace name";
case ISO_EXTF_TOO_OFTEN:
return "Too many references on a single external filter command";
case ISO_ZLIB_NOT_ENABLED:
return "Use of zlib was not enabled at compile time";
case ISO_ZISOFS_TOO_LARGE:
return "Cannot apply zisofs filter to file >= 4 GiB";
case ISO_FILTER_WRONG_INPUT:
return "Filter input differs from previous run";
case ISO_ZLIB_COMPR_ERR:
return "zlib compression/decompression error";
case ISO_ZISOFS_WRONG_INPUT:
return "Input stream is not in zisofs format";
case ISO_ZISOFS_PARAM_LOCK:
return "Cannot set global zisofs parameters while filters exist";
case ISO_ZLIB_EARLY_EOF:
return "Premature EOF of zlib input stream";
default:
return "Unknown error";
}
@ -213,7 +269,7 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
{
char msg[MAX_MSG_LEN];
va_list ap;
/* when called with ISO_CANCELED, we don't need to submit any message */
if (errcode == ISO_CANCELED && fmt == NULL) {
return ISO_CANCELED;
@ -227,12 +283,12 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
strncpy(msg, iso_error_to_msg(errcode), MAX_MSG_LEN);
}
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(errcode),
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(errcode),
ISO_ERR_SEV(errcode), ISO_ERR_PRIO(errcode), msg, 0, 0);
if (causedby != 0) {
snprintf(msg, MAX_MSG_LEN, " > Caused by: %s",
snprintf(msg, MAX_MSG_LEN, " > Caused by: %s",
iso_error_to_msg(causedby));
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(causedby),
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(causedby),
LIBISO_MSGS_SEV_NOTE, LIBISO_MSGS_PRIO_LOW, msg, 0, 0);
if (ISO_ERR_SEV(causedby) == LIBISO_MSGS_SEV_FATAL) {
return ISO_CANCELED;
@ -246,11 +302,11 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
}
}
/**
/**
* Control queueing and stderr printing of messages from libisofs.
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
* "NOTE", "UPDATE", "DEBUG", "ALL".
*
*
* @param queue_severity Gives the minimum limit for messages to be queued.
* Default: "NEVER". If you queue messages then you
* must consume them by iso_msgs_obtain().
@ -259,7 +315,7 @@ int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
* @param print_id A text prefix to be printed before the message.
* @return >0 for success, <=0 for error
*/
int iso_set_msgs_severities(char *queue_severity, char *print_severity,
int iso_set_msgs_severities(char *queue_severity, char *print_severity,
char *print_id)
{
int ret, queue_sevno, print_sevno;
@ -277,15 +333,15 @@ int iso_set_msgs_severities(char *queue_severity, char *print_severity,
return 1;
}
/**
/**
* Obtain the oldest pending libisofs message from the queue which has at
* least the given minimum_severity. This message and any older message of
* lower severity will get discarded from the queue and is then lost forever.
*
*
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
* "NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
* will discard the whole queue.
*
*
* @param error_code Will become a unique error code as listed in messages.h
* @param imgid Id of the image that was issued the message.
* @param msg_text Must provide at least ISO_MSGS_MESSAGE_LEN bytes.
@ -305,7 +361,7 @@ int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
ret = libiso_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
if (ret <= 0)
return 0;
ret = libiso_msgs_obtain(libiso_msgr, &item, minimum_sevno,
ret = libiso_msgs_obtain(libiso_msgr, &item, minimum_sevno,
LIBISO_MSGS_PRIO_ZERO, 0);
if (ret <= 0)
goto ex;
@ -319,7 +375,7 @@ int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
ret = libiso_msgs_item_get_origin(item, &timestamp, &pid, imgid, 0);
if (ret <= 0)
goto ex;
severity[0]= 0;
ret = libiso_msgs_item_get_rank(item, &sevno, &priority, 0);
if (ret <= 0)
@ -335,12 +391,66 @@ int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
return ret;
}
/* ts A80222 : derived from libburn/init.c:burn_msgs_submit()
*/
int iso_msgs_submit(int error_code, char msg_text[], int os_errno,
char severity[], int origin)
{
int ret, sevno;
ret = libiso_msgs__text_to_sev(severity, &sevno, 0);
if (ret <= 0)
sevno = LIBISO_MSGS_SEV_ALL;
if (error_code <= 0) {
switch(sevno) {
case LIBISO_MSGS_SEV_ABORT: error_code = 0x00040000;
break; case LIBISO_MSGS_SEV_FATAL: error_code = 0x00040001;
break; case LIBISO_MSGS_SEV_SORRY: error_code = 0x00040002;
break; case LIBISO_MSGS_SEV_WARNING: error_code = 0x00040003;
break; case LIBISO_MSGS_SEV_HINT: error_code = 0x00040004;
break; case LIBISO_MSGS_SEV_NOTE: error_code = 0x00040005;
break; case LIBISO_MSGS_SEV_UPDATE: error_code = 0x00040006;
break; case LIBISO_MSGS_SEV_DEBUG: error_code = 0x00040007;
break; default: error_code = 0x00040008;
}
}
ret = libiso_msgs_submit(libiso_msgr, origin, error_code,
sevno, LIBISO_MSGS_PRIO_HIGH, msg_text, os_errno, 0);
return ret;
}
/* ts A80222 : derived from libburn/init.c:burn_text_to_sev()
*/
int iso_text_to_sev(char *severity_name, int *sevno)
{
int ret;
ret = libiso_msgs__text_to_sev(severity_name, sevno, 0);
if (ret <= 0)
*sevno = LIBISO_MSGS_SEV_FATAL;
return ret;
}
/* ts A80222 : derived from libburn/init.c:burn_sev_to_text()
*/
int iso_sev_to_text(int severity_number, char **severity_name)
{
int ret;
ret = libiso_msgs__sev_to_text(severity_number, severity_name, 0);
return ret;
}
/**
* Return the messenger object handle used by libisofs. This handle
* may be used by related libraries to their own compatible
* messenger objects and thus to direct their messages to the libisofs
* message queue. See also: libburn, API function burn_set_messenger().
*
*
* @return the handle. Do only use with compatible
*/
void *iso_get_messenger()
@ -362,3 +472,13 @@ int iso_error_get_code(int e)
{
return ISO_ERR_CODE(e);
}
/* ts A80222 */
int iso_report_errfile(char *path, int error_code, int os_errno, int flag)
{
libiso_msgs_submit(libiso_msgr, 0, error_code,
LIBISO_MSGS_SEV_ERRFILE, LIBISO_MSGS_PRIO_HIGH,
path, os_errno, 0);
return(1);
}

View File

@ -37,4 +37,13 @@ void iso_msg_debug(int imgid, const char *fmt, ...);
*/
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...);
/* ts A80222 */
/* To be called with events which report incidents with individual input
files from the local filesystem. Not with image nodes, files containing an
image or similar file-like objects.
*/
int iso_report_errfile(char *path, int error_code, int os_errno, int flag);
#endif /*MESSAGES_H_*/

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#ifndef LIBISO_NODE_H_
@ -20,17 +21,14 @@
#include <unistd.h>
#include <stdint.h>
/* #define LIBISO_EXTENDED_INFORMATION */
#ifdef LIBISO_EXTENDED_INFORMATION
/**
* The extended information is a way to attach additional information to each
* IsoNode. External applications may want to use this extension system to
* IsoNode. External applications may want to use this extension system to
* store application speficic information related to each node. On the other
* side, libisofs may make use of this struct to attach information to nodes in
* some particular, uncommon, cases, without incrementing the size of the
* IsoNode struct.
*
*
* It is implemented like a chained list.
*/
typedef struct iso_extended_info IsoExtendedInfo;
@ -40,41 +38,39 @@ struct iso_extended_info {
* Next struct in the chain. NULL if it is the last item
*/
IsoExtendedInfo *next;
/**
* Function to handle this particular extended information. The function
* pointer acts as an identifier for the type of the information. Structs
* with same information type must use the same function.
*
*
* @param data
* Attached data
* @param flag
* What to do with the data. At this time the following values are
* What to do with the data. At this time the following values are
* defined:
* -> 1 the data must be freed
* @return
* 1
*/
int (*process)(void *data, int flag);
iso_node_xinfo_func process;
/**
* Pointer to information specific data.
*/
void *data;
};
#endif
/**
*
*
*/
struct Iso_Node
{
/*
* Initilized to 1, originally owned by user, until added to another node.
* Then it is owned by the parent node, so the user must take his own ref
* Then it is owned by the parent node, so the user must take his own ref
* if needed. With the exception of the creation functions, none of the
* other libisofs functions that return an IsoNode increment its
* other libisofs functions that return an IsoNode increment its
* refcount. This is responsablity of the client, if (s)he needs it.
*/
int refcount;
@ -102,12 +98,10 @@ struct Iso_Node
*/
IsoNode *next;
#ifdef LIBISO_EXTENDED_INFORMATION
/**
* Extended information for the node.
*/
IsoExtendedInfo *xinfo;
#endif
};
struct Iso_Dir
@ -122,17 +116,14 @@ struct Iso_File
{
IsoNode node;
/**
* Location of a file extent in a ms disc, 0 for newly added file
*/
uint32_t msblock;
unsigned int from_old_session : 1;
/**
/**
* It sorts the order in which the file data is written to the CD image.
* Higher weighting files are written at the beginning of image
* Higher weighting files are written at the beginning of image
*/
int sort_weight;
IsoStream *stream;
IsoStream *stream; /* Knows fs_id, st_dev, and st_ino */
};
struct Iso_Symlink
@ -140,12 +131,54 @@ struct Iso_Symlink
IsoNode node;
char *dest;
#ifdef Libisofs_hardlink_matcheR
/* If the IsoNode represents an object in an existing filesystem then
the following three numbers should unique identify it.
(0,0,0) will always be taken as unique.
*/
unsigned int fs_id;
dev_t st_dev;
ino_t st_ino;
#endif
};
struct Iso_Special
{
IsoNode node;
dev_t dev;
#ifdef Libisofs_hardlink_matcheR
/* If the IsoNode represents an object in an existing filesystem then
the following three numbers should unique identify it.
(0,0,0) will always be taken as unique.
*/
unsigned int fs_id;
dev_t st_dev;
ino_t st_ino;
#endif
};
struct iso_dir_iter_iface
{
int (*next)(IsoDirIter *iter, IsoNode **node);
int (*has_next)(IsoDirIter *iter);
void (*free)(IsoDirIter *iter);
int (*take)(IsoDirIter *iter);
int (*remove)(IsoDirIter *iter);
/**
* This is called just before remove a node from a directory. The iterator
* may want to update its internal state according to this.
*/
void (*notify_child_taken)(IsoDirIter *iter, IsoNode *node);
};
/**
@ -153,34 +186,38 @@ struct Iso_Special
*/
struct Iso_Dir_Iter
{
const IsoDir *dir;
IsoNode *pos;
struct iso_dir_iter_iface *class;
/* the directory this iterator iterates over */
IsoDir *dir;
void *data;
};
int iso_node_new_root(IsoDir **root);
/**
* Create a new IsoDir. Attributes, uid/gid, timestamps, etc are set to
* Create a new IsoDir. Attributes, uid/gid, timestamps, etc are set to
* default (0) values. You must set them.
*
*
* @param name
* Name for the node. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* Name for the node. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* allowed.
* @param dir
*
*
* @return
* 1 on success, < 0 on error.
*/
int iso_node_new_dir(char *name, IsoDir **dir);
/**
* Create a new file node. Attributes, uid/gid, timestamps, etc are set to
* Create a new file node. Attributes, uid/gid, timestamps, etc are set to
* default (0) values. You must set them.
*
*
* @param name
* Name for the node. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* Name for the node. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* allowed.
* @param stream
* Source for file contents. The reference is taken by the node,
@ -193,14 +230,14 @@ int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file);
/**
* Creates a new IsoSymlink node. Attributes, uid/gid, timestamps, etc are set
* to default (0) values. You must set them.
*
*
* @param name
* name for the new symlink. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* name for the new symlink. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* allowed.
* @param dest
* destination of the link. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* destination of the link. It is not strdup() so you shouldn't use this
* reference when this function returns successfully. NULL is not
* allowed.
* @param link
* place where to store a pointer to the newly created link.
@ -214,22 +251,22 @@ int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link);
* an special file is a block device, a character device, a FIFO (named pipe)
* or a socket. You can choose the specific kind of file you want to add
* by setting mode propertly (see man 2 stat).
*
* Note that special files are only written to image when Rock Ridge
*
* Note that special files are only written to image when Rock Ridge
* extensions are enabled. Moreover, a special file is just a directory entry
* in the image tree, no data is written beyond that.
*
* Owner and hidden atts are taken from parent. You can modify any of them
*
* Owner and hidden atts are taken from parent. You can modify any of them
* later.
*
*
* @param name
* name for the new special file. It is not strdup() so you shouldn't use
* this reference when this function returns successfully. NULL is not
* name for the new special file. It is not strdup() so you shouldn't use
* this reference when this function returns successfully. NULL is not
* allowed.
* @param mode
* file type and permissions for the new node. Note that you can't
* specify any kind of file here, only special types are allowed. i.e,
* S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK,
* S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK,
* S_IFREG and S_IFDIR aren't.
* @param dev
* device ID, equivalent to the st_rdev field in man 2 stat.
@ -238,12 +275,12 @@ int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link);
* @return
* 1 on success, < 0 otherwise
*/
int iso_node_new_special(char *name, mode_t mode, dev_t dev,
int iso_node_new_special(char *name, mode_t mode, dev_t dev,
IsoSpecial **special);
/**
* Check if a given name is valid for an iso node.
*
*
* @return
* 1 if yes, 0 if not
*/
@ -251,7 +288,7 @@ int iso_node_is_valid_name(const char *name);
/**
* Check if a given path is valid for the destination of a link.
*
*
* @return
* 1 if yes, 0 if not
*/
@ -259,7 +296,7 @@ int iso_node_is_valid_link_dest(const char *dest);
/**
* Find the position where to insert a node
*
*
* @param dir
* A valid dir. It can't be NULL
* @param name
@ -271,7 +308,7 @@ void iso_dir_find(IsoDir *dir, const char *name, IsoNode ***pos);
/**
* Check if a node with the given name exists in a dir.
*
*
* @param dir
* A valid dir. It can't be NULL
* @param name
@ -286,21 +323,132 @@ int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos);
/**
* Inserts a given node in a dir, at the specified position.
*
*
* @param dir
* Dir where to insert. It can't be NULL
* @param node
* The node to insert. It can't be NULL
* @param pos
* Position where the node will be inserted. It is a pointer previously
* obtained with a call to iso_dir_exists() or iso_dir_find().
* obtained with a call to iso_dir_exists() or iso_dir_find().
* It can't be NULL.
* @param replace
* @param replace
* Whether to replace an old node with the same name with the new node.
* @return
* If success, number of children in dir. < 0 on error
* If success, number of children in dir. < 0 on error
*/
int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
enum iso_replace_mode replace);
/**
* Add a new iterator to the registry. The iterator register keeps track of
* all iterators being used, and are notified when directory structure
* changes.
*/
int iso_dir_iter_register(IsoDirIter *iter);
/**
* Unregister a directory iterator.
*/
void iso_dir_iter_unregister(IsoDirIter *iter);
void iso_notify_dir_iters(IsoNode *node, int flag);
/**
* See API function iso_node_set_permissions()
*
* @param flag bit0= do not adjust ACL
* @return >0 success , <0 error
*/
int iso_node_set_perms_internal(IsoNode *node, mode_t mode, int flag);
/**
* Like iso_node_get_acl_text() with param node replaced by aa_string and
* st_mode from where to obtain the ACLs. All other parameter specs apply.
*/
int iso_aa_get_acl_text(unsigned char *aa_string, mode_t st_mode,
char **access_text, char **default_text, int flag);
/**
* Backend of iso_node_get_attrs() with parameter node replaced by the
* AAIP string from where to get the attribute list.
* All other parameter specs apply.
*/
int iso_aa_get_attrs(unsigned char *aa_string, size_t *num_attrs,
char ***names, size_t **value_lengths, char ***values, int flag);
/**
* Search given name. Eventually calloc() and copy value. Add trailing 0 byte
* for caller convenience.
*
* @return 1= found , 0= not found , <0 error
*/
int iso_aa_lookup_attr(unsigned char *aa_string, char *name,
size_t *value_length, char **value, int flag);
/**
* Function to identify and manage ZF parameters which do not stem from ZF
* fields (those are known to the FileSource) and do not stem from filters
* ("ziso" knows them globally, "osiz" knows them individually) but rather
* from an inspection of the file content header for zisofs magic number and
* plausible parameters.
* The parameters get attached in struct zisofs_zf_info as xinfo to an IsoNode.
*/
int zisofs_zf_xinfo_func(void *data, int flag);
/**
* Parameter structure which is to be managed by zisofs_zf_xinfo_func.
*/
struct zisofs_zf_info {
uint32_t uncompressed_size;
uint8_t header_size_div4;
uint8_t block_size_log2;
};
/**
* Checks whether a file effectively bears a zisofs file header and eventually
* marks this by a struct zisofs_zf_info as xinfo of the file node.
* @param flag bit0= inquire the most original stream of the file
* bit1= permission to overwrite existing zisofs_zf_info
* bit2= if no zisofs header is found:
create xinfo with parameters which indicate no zisofs
* @return 1= zf xinfo added, 0= no zisofs data found ,
* 2= found existing zf xinfo and flag bit1 was not set
* <0 means error
*/
int iso_file_zf_by_magic(IsoFile *file, int flag);
/*
* @param flag
* bit0= do only retrieve id if node is in imported ISO image
* or has an explicit xinfo inode number
* @return
* 1= reply is valid from stream, 2= reply is valid from xinfo
* 0= no id available, <0= error
* (fs_id, dev_id, ino_id) will be (0,0,0) in case of return <= 0
*/
int iso_node_get_id(IsoNode *node, unsigned int *fs_id, dev_t *dev_id,
ino_t *ino_id, int flag);
/* Set a new unique inode ISO image number to the given node.
* This number shall eventually persist during image generation.
*/
int iso_node_set_unique_id(IsoNode *node, IsoImage *image, int flag);
/* Use this with extreme care. Duplicate inode numbers will indicate hardlink
* relationship between the nodes.
*/
int iso_node_set_ino(IsoNode *node, ino_t ino, int flag);
/*
* @param flag
* bit0= compare stat properties and attributes
* bit1= treat all nodes with image ino == 0 as unique
* (those with 0,0,0 are treated as unique anyway)
*/
int iso_node_cmp_flag(IsoNode *n1, IsoNode *n2, int flag);
#endif /*LIBISO_NODE_H_*/

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2007 Mario Danic
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
@ -9,18 +10,29 @@
/**
* This header defines the functions and structures needed to add RockRidge
* extensions to an ISO image.
* extensions to an ISO image. It also handles AAIP and zisofs extensions.
*
* References:
*
* - SUSP (IEEE 1281).
* System Use Sharing Protocol, draft standard version 1.12.
* See ftp://ftp.ymi.com/pub/rockridge/susp112.ps
*
* - RRIP (IEEE 1282)
* Rock Ridge Interchange Protocol, Draft Standard version 1.12.
* See ftp://ftp.ymi.com/pub/rockridge/rrip112.ps
*
* - ECMA-119 (ISO-9660)
* Volume and File Structure of CDROM for Information Interchange.
* Volume and File Structure of CDROM for Information Interchange. See
* http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
*
* - AAIP
* Arbitrary Attribute Interchange Protocol. See doc/susp_aaip_2_0.txt
*
* - zisofs
* Blockwise compression of data file content with transparent read support
* in the Linux kernel. See doc/zisofs_format.txt
*
*/
#ifndef LIBISO_ROCKRIDGE_H
@ -28,6 +40,7 @@
#include "ecma119.h"
#define SUSP_SIG(entry, a, b) ((entry->sig[0] == a) && (entry->sig[1] == b))
/**
@ -115,6 +128,28 @@ struct rr_SL {
uint8_t comps[1];
};
/** Outdated Arbitrary Attribute (AAIP, see doc/susp_aaip_1_0.txt)
* It collided with pre-SUSP Apple AA field.
*/
struct aaip_AA {
uint8_t flags[1];
uint8_t comps[1];
};
/** Arbitrary Attribute (AAIP, see doc/susp_aaip_2_0.txt) */
struct aaip_AL {
uint8_t flags[1];
uint8_t comps[1];
};
/** zisofs entry (see doc/zisofs_format.txt) */
struct zisofs_ZF {
uint8_t parameters[1]; /* begins with BP 5 */
};
/**
* Struct for a SUSP System User Entry (SUSP, 4.1)
*/
@ -133,6 +168,9 @@ struct susp_sys_user_entry
struct rr_NM NM;
struct rr_CL CL;
struct rr_SL SL;
struct aaip_AA AA;
struct aaip_AL AL;
struct zisofs_ZF ZF;
} data; /* 5 to 4+len_sue */
};
@ -225,7 +263,9 @@ void susp_iter_free(SuspIterator *iter);
* Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
*
* @return
* 1 on success, < 0 on error
* < 0 on error
* 1 on success with no inode number,
* 2 on success with inode number,
*/
int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st);
@ -264,4 +304,45 @@ int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont);
*/
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st);
/**
* Collects the AAIP field string from single AAIP fields.
* (see doc/susp_aaip_1_0.txt)
* @param aa_string Storage location of the emerging string.
* Begin with *aa_string == NULL, or own malloc() storage.
* @param aa_size Current allocated size of aa_string.
* Begin with *aa_size == 0, or own storage size.
* @param aa_len Current occupied size of aa_string.
* Begin with *aa_len == 0
* @param prev_field Returns the index of start of the previous field
* in the string.
* @param is_done The current completion state of the AAIP field string.
* Fields will be ignored as soon as it is 1.
* Begin with *is_done == 0
* @param flag Unused yet. Submit 0.
* @return
* 1 on success, < 0 on error
*/
int read_aaip_AA(struct susp_sys_user_entry *sue,
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
size_t *prev_field, int *is_done, int flag);
/**
* Collects the AAIP field string from single AL fields.
* (see doc/susp_aaip_2_0.txt)
*/
int read_aaip_AL(struct susp_sys_user_entry *sue,
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
size_t *prev_field, int *is_done, int flag);
/**
* Reads the zisofs parameters from a ZF field (see doc/zisofs_format.txt).
*
* @return
* 1 on success, < 0 on error
*/
int read_zisofs_ZF(struct susp_sys_user_entry *zf, uint8_t algorithm[2],
uint8_t *header_size_div4, uint8_t *block_size_log2,
uint32_t *uncompressed_size, int flag);
#endif /* LIBISO_ROCKRIDGE_H */

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2007 Vreixo Formoso
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
@ -7,8 +8,8 @@
*/
/*
* This file contains functions related to the reading of SUSP and
* Rock Ridge extensions on an ECMA-119 image.
* This file contains functions related to the reading of SUSP,
* Rock Ridge and AAIP extensions on an ECMA-119 image.
*/
#include "libisofs.h"
@ -168,11 +169,14 @@ int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st)
st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
st->st_ino = 0;
if (px->len_sue[0] == 44) {
/* this corresponds to RRIP 1.12, so we have inode serial number */
st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
/* Indicate that st_ino is valid */
return 2;
}
return ISO_SUCCESS;
return 1;
}
/**
@ -402,6 +406,8 @@ int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
*/
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
{
int high_shift= 0;
if (pn == NULL || pn == NULL) {
return ISO_NULL_POINTER;
}
@ -413,7 +419,170 @@ int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
return ISO_WRONG_RR;
}
/* (dev_t << 32) causes compiler warnings on FreeBSD
because sizeof(dev_t) is 4.
*/
st->st_rdev = (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
if (sizeof(st->st_rdev) > 4) {
high_shift = 32;
st->st_rdev |= (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) <<
high_shift);
}
/* was originally:
st->st_rdev = (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) << 32)
|| (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
| (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
*/
return ISO_SUCCESS;
}
/* AA is the field signature of AAIP versions < 2.0
*/
int read_aaip_AA(struct susp_sys_user_entry *sue,
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
size_t *prev_field, int *is_done, int flag)
{
unsigned char *aapt;
if (*is_done) {
/* To coexist with Apple ISO :
Gracefully react on eventually trailing Apple AA
*/
if (sue->version[0] != 1 || sue->len_sue[0] == 7)
return ISO_SUCCESS;
return ISO_WRONG_RR;
}
/* Eventually create or grow storage */
if (*aa_size == 0 || *aa_string == NULL) {
/* Gracefully react on eventually leading Apple AA
*/
if (sue->version[0] != 1 || sue->len_sue[0] < 9) {
return ISO_SUCCESS;
}
*aa_size = *aa_len + sue->len_sue[0];
*aa_string = calloc(*aa_size, 1);
*aa_len = 0;
} else if (*aa_len + sue->len_sue[0] > *aa_size) {
if (sue->version[0] != 1) {
/* Apple ISO within the AAIP field group is not AAIP compliant
*/
return ISO_WRONG_RR;
}
*aa_size += *aa_len + sue->len_sue[0];
*aa_string = realloc(*aa_string, *aa_size);
}
if (*aa_string == NULL)
return ISO_OUT_OF_MEM;
if (*aa_len > 0) {
/* Mark prev_field as being continued */
(*aa_string)[*prev_field + 4] = 1;
}
*prev_field = *aa_len;
/* Compose new SUSP header with signature aa[], cont == 0 */
aapt = *aa_string + *aa_len;
aapt[0] = 'A';
aapt[1] = 'L';
aapt[2] = sue->len_sue[0];
aapt[3] = 1;
aapt[4] = 0;
/* Append sue payload */
memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
*is_done = !(sue->data.AL.flags[0] & 1);
*aa_len += sue->len_sue[0];
return ISO_SUCCESS;
}
/* AL is the obsolete field signature of AAIP versions >= 2.0
*/
int read_aaip_AL(struct susp_sys_user_entry *sue,
unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
size_t *prev_field, int *is_done, int flag)
{
unsigned char *aapt;
if (*is_done)
return ISO_WRONG_RR;
if (sue->version[0] != 1)
return ISO_WRONG_RR;
/* Eventually create or grow storage */
if (*aa_size == 0 || *aa_string == NULL) {
*aa_size = *aa_len + sue->len_sue[0];
*aa_string = calloc(*aa_size, 1);
*aa_len = 0;
} else if (*aa_len + sue->len_sue[0] > *aa_size) {
*aa_size += *aa_len + sue->len_sue[0];
*aa_string = realloc(*aa_string, *aa_size);
}
if (*aa_string == NULL)
return ISO_OUT_OF_MEM;
if (*aa_len > 0) {
/* Mark prev_field as being continued */
(*aa_string)[*prev_field + 4] = 1;
}
*prev_field = *aa_len;
/* Compose new SUSP header with signature aa[], cont == 0 */
aapt = *aa_string + *aa_len;
aapt[0] = 'A';
aapt[1] = 'L';
aapt[2] = sue->len_sue[0];
aapt[3] = 1;
aapt[4] = 0;
/* Append sue payload */
memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
*is_done = !(sue->data.AL.flags[0] & 1);
*aa_len += sue->len_sue[0];
return ISO_SUCCESS;
}
/**
* Reads the zisofs parameters from a ZF field (see doc/zisofs_format.txt).
*
* @return
* 1 on success, < 0 on error
*/
int read_zisofs_ZF(struct susp_sys_user_entry *zf, uint8_t algorithm[2],
uint8_t *header_size_div4, uint8_t *block_size_log2,
uint32_t *uncompressed_size, int flag)
{
if (zf == NULL) {
return ISO_NULL_POINTER;
}
if (zf->sig[0] != 'Z' || zf->sig[1] != 'F') {
return ISO_WRONG_ARG_VALUE;
}
if (zf->len_sue[0] != 16) {
return ISO_WRONG_RR;
}
algorithm[0] = zf->data.ZF.parameters[0];
algorithm[1] = zf->data.ZF.parameters[1];
*header_size_div4 = zf->data.ZF.parameters[2];
*block_size_log2 = zf->data.ZF.parameters[3];
*uncompressed_size = iso_read_bb(&(zf->data.ZF.parameters[4]), 4, NULL);
return ISO_SUCCESS;
}

View File

@ -1,8 +1,9 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
@ -13,19 +14,12 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdio.h>
ino_t serial_id = (ino_t)1;
ino_t mem_serial_id = (ino_t)1;
typedef struct
{
IsoFileSource *src;
/* key for file identification inside filesystem */
dev_t dev_id;
ino_t ino_id;
off_t size; /**< size of this file */
} FSrcStreamData;
ino_t cut_out_serial_id = (ino_t)1;
static
int fsrc_open(IsoStream *stream)
@ -114,7 +108,7 @@ void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
{
FSrcStreamData *data;
IsoFilesystem *fs;
data = (FSrcStreamData*)stream->data;
fs = iso_file_source_get_filesystem(data->src);
@ -123,14 +117,6 @@ void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
*ino_id = data->ino_id;
}
static
char *fsrc_get_name(IsoStream *stream)
{
FSrcStreamData *data;
data = (FSrcStreamData*)stream->data;
return iso_file_source_get_path(data->src);
}
static
void fsrc_free(IsoStream *stream)
{
@ -140,15 +126,37 @@ void fsrc_free(IsoStream *stream)
free(data);
}
static
int fsrc_update_size(IsoStream *stream)
{
int ret;
struct stat info;
IsoFileSource *src;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
src = ((FSrcStreamData*)stream->data)->src;
ret = iso_file_source_stat(src, &info);
if (ret < 0) {
return ret;
}
((FSrcStreamData*)stream->data)->size = info.st_size;
return ISO_SUCCESS;
}
IsoStreamIface fsrc_stream_class = {
1, /* update_size is defined for this stream */
"fsrc",
fsrc_open,
fsrc_close,
fsrc_get_size,
fsrc_read,
fsrc_is_repeatable,
fsrc_get_id,
fsrc_get_name,
fsrc_free
fsrc_free,
fsrc_update_size
};
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
@ -169,7 +177,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
if (S_ISDIR(info.st_mode)) {
return ISO_FILE_IS_DIR;
}
/* check for read access to contents */
r = iso_file_source_access(src);
if (r < 0) {
@ -181,7 +189,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(FSrcStreamData));
if (str == NULL) {
if (data == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
@ -189,7 +197,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
/* take the ref to IsoFileSource */
data->src = src;
data->size = info.st_size;
/* get the id numbers */
{
IsoFilesystem *fs;
@ -198,7 +206,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
fs_id = fs->get_id(fs);
if (fs_id == 0) {
/*
/*
* the filesystem implementation is unable to provide valid
* st_dev and st_ino fields. Use serial_id.
*/
@ -219,6 +227,220 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
}
int iso_stream_get_src_zf(IsoStream *stream, int *header_size_div4,
int *block_size_log2, uint32_t *uncompressed_size,
int flag)
{
int ret;
FSrcStreamData *data;
IsoFileSource *src;
/* Intimate friendship with libisofs/fs_image.c */
int iso_ifs_source_get_zf(IsoFileSource *src, int *header_size_div4,
int *block_size_log2, uint32_t *uncompressed_size, int flag);
if (stream->class != &fsrc_stream_class)
return 0;
data = stream->data;
src = data->src;
ret = iso_ifs_source_get_zf(src, header_size_div4, block_size_log2,
uncompressed_size, 0);
return ret;
}
struct cut_out_stream
{
IsoFileSource *src;
/* key for file identification inside filesystem */
dev_t dev_id;
ino_t ino_id;
off_t offset; /**< offset where read begins */
off_t size; /**< size of this file */
off_t pos; /* position on the file for read */
};
static
int cut_out_open(IsoStream *stream)
{
int ret;
struct stat info;
IsoFileSource *src;
struct cut_out_stream *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
src = data->src;
ret = iso_file_source_stat(data->src, &info);
if (ret < 0) {
return ret;
}
ret = iso_file_source_open(src);
if (ret < 0) {
return ret;
}
{
off_t ret;
if (data->offset > info.st_size) {
/* file is smaller than expected */
ret = iso_file_source_lseek(src, info.st_size, 0);
} else {
ret = iso_file_source_lseek(src, data->offset, 0);
}
if (ret < 0) {
return (int) ret;
}
}
data->pos = 0;
if (data->offset + data->size > info.st_size) {
return 3; /* file smaller than expected */
} else {
return ISO_SUCCESS;
}
}
static
int cut_out_close(IsoStream *stream)
{
IsoFileSource *src;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
src = ((struct cut_out_stream*)stream->data)->src;
return iso_file_source_close(src);
}
static
off_t cut_out_get_size(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
return data->size;
}
static
int cut_out_read(IsoStream *stream, void *buf, size_t count)
{
struct cut_out_stream *data = stream->data;
count = (size_t)MIN(data->size - data->pos, count);
if (count == 0) {
return 0;
}
return iso_file_source_read(data->src, buf, count);
}
static
int cut_out_is_repeatable(IsoStream *stream)
{
/* reg files are always repeatable */
return 1;
}
static
void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
ino_t *ino_id)
{
FSrcStreamData *data;
IsoFilesystem *fs;
data = (FSrcStreamData*)stream->data;
fs = iso_file_source_get_filesystem(data->src);
*fs_id = fs->get_id(fs);
*dev_id = data->dev_id;
*ino_id = data->ino_id;
}
static
void cut_out_free(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
iso_file_source_unref(data->src);
free(data);
}
/*
* TODO update cut out streams to deal with update_size(). Seems hard.
*/
IsoStreamIface cut_out_stream_class = {
0,
"cout",
cut_out_open,
cut_out_close,
cut_out_get_size,
cut_out_read,
cut_out_is_repeatable,
cut_out_get_id,
cut_out_free
};
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
IsoStream **stream)
{
int r;
struct stat info;
IsoStream *str;
struct cut_out_stream *data;
if (src == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (size == 0) {
return ISO_WRONG_ARG_VALUE;
}
r = iso_file_source_stat(src, &info);
if (r < 0) {
return r;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset > info.st_size) {
return ISO_FILE_OFFSET_TOO_BIG;
}
/* check for read access to contents */
r = iso_file_source_access(src);
if (r < 0) {
return r;
}
str = malloc(sizeof(IsoStream));
if (str == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(struct cut_out_stream));
if (data == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
/* take a new ref to IsoFileSource */
data->src = src;
iso_file_source_ref(src);
data->offset = offset;
data->size = MIN(info.st_size - offset, size);
/* get the id numbers */
data->dev_id = (dev_t) 0;
data->ino_id = cut_out_serial_id++;
str->refcount = 1;
str->data = data;
str->class = &cut_out_stream_class;
*stream = str;
return ISO_SUCCESS;
}
typedef struct
{
@ -237,7 +459,7 @@ int mem_open(IsoStream *stream)
}
data = (MemStreamData*)stream->data;
if (data->offset != -1) {
return ISO_FILE_ALREADY_OPENNED;
return ISO_FILE_ALREADY_OPENED;
}
data->offset = 0;
return ISO_SUCCESS;
@ -252,7 +474,7 @@ int mem_close(IsoStream *stream)
}
data = (MemStreamData*)stream->data;
if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
data->offset = -1;
return ISO_SUCCESS;
@ -279,15 +501,15 @@ int mem_read(IsoStream *stream, void *buf, size_t count)
return ISO_WRONG_ARG_VALUE;
}
data = stream->data;
if (data->offset == -1) {
return ISO_FILE_NOT_OPENNED;
return ISO_FILE_NOT_OPENED;
}
if (data->offset >= data->size) {
return 0; /* EOF */
}
len = MIN(count, data->size - data->offset);
memcpy(buf, data->buf + data->offset, len);
data->offset += len;
@ -311,12 +533,6 @@ void mem_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
*ino_id = data->ino_id;
}
static
char *mem_get_name(IsoStream *stream)
{
return strdup("[MEMORY SOURCE]");
}
static
void mem_free(IsoStream *stream)
{
@ -327,20 +543,21 @@ void mem_free(IsoStream *stream)
}
IsoStreamIface mem_stream_class = {
0,
"mem ",
mem_open,
mem_close,
mem_get_size,
mem_read,
mem_is_repeatable,
mem_get_id,
mem_get_name,
mem_free
};
/**
* Create a stream for reading from a arbitrary memory buffer.
* When the Stream refcount reach 0, the buffer is free(3).
*
*
* @return
* 1 sucess, < 0 error
*/
@ -420,6 +637,13 @@ int iso_stream_is_repeatable(IsoStream *stream)
return stream->class->is_repeatable(stream);
}
inline
int iso_stream_update_size(IsoStream *stream)
{
IsoStreamIface* class = stream->class;
return (class->version >= 1) ? class->update_size(stream) : 0;
}
inline
void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
ino_t *ino_id)
@ -427,8 +651,182 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
stream->class->get_id(stream, fs_id, dev_id, ino_id);
}
inline
char *iso_stream_get_name(IsoStream *stream)
void iso_stream_get_file_name(IsoStream *stream, char *name)
{
return stream->class->get_name(stream);
char *type = stream->class->type;
if (!strncmp(type, "fsrc", 4)) {
FSrcStreamData *data = stream->data;
char *path = iso_file_source_get_path(data->src);
strncpy(name, path, PATH_MAX);
free(path);
} else if (!strncmp(type, "boot", 4)) {
strcpy(name, "BOOT CATALOG");
} else if (!strncmp(type, "mem ", 4)) {
strcpy(name, "MEM SOURCE");
} else if (!strncmp(type, "extf", 4)) {
strcpy(name, "EXTERNAL FILTER");
} else {
strcpy(name, "UNKNOWN SOURCE");
}
}
IsoStream *iso_stream_get_input_stream(IsoStream *stream, int flag)
{
IsoStreamIface* class;
if (stream == NULL) {
return NULL;
}
class = stream->class;
if (class->version < 2)
return NULL;
return class->get_input_stream(stream, 0);
}
char *iso_stream_get_source_path(IsoStream *stream, int flag)
{
char *path = NULL, ivd[80], *raw_path = NULL;
if (stream == NULL) {
return NULL;
}
if (stream->class == &fsrc_stream_class) {
FSrcStreamData *fsrc_data = stream->data;
path = iso_file_source_get_path(fsrc_data->src);
} else if (stream->class == &cut_out_stream_class) {
struct cut_out_stream *cout_data = stream->data;
raw_path = iso_file_source_get_path(cout_data->src);
sprintf(ivd, " %.f %.f",
(double) cout_data->offset, (double) cout_data->size);
path= calloc(strlen(raw_path) + strlen(ivd) + 1, 1);
if (path == NULL) {
goto ex;
}
strcpy(path, raw_path);
strcat(path, ivd);
}
ex:;
if (raw_path != NULL)
free(raw_path);
return path;
}
/* @return 1 = ok , 0 = not an ISO image stream , <0 = error */
int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag)
{
if (stream == NULL) {
return ISO_NULL_POINTER;
}
if (stream->class == &fsrc_stream_class) {
FSrcStreamData *fsrc_data = stream->data;
fsrc_data->ino_id = ino;
return 1;
}
return 0;
}
/* API */
int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
{
int ret;
unsigned int fs_id1, fs_id2;
dev_t dev_id1, dev_id2;
ino_t ino_id1, ino_id2;
off_t size1, size2;
FSrcStreamData *fssd1, *fssd2;
/* <<<
#define Libisofs_stream_cmp_ino_debuG 1
*/
#ifdef Libisofs_stream_cmp_ino_debuG
static int report_counter = 0;
static int debug = 1;
#endif /* Libisofs_stream_cmp_ino_debuG */
if (s1 == s2)
return 0;
if (s1 == NULL)
return -1;
if (s2 == NULL)
return 1;
if (s1->class->version >= 3 && !(flag & 1)) {
/* Filters may have smarter methods to compare themselves with others */
ret = s1->class->cmp_ino(s1, s2);
return ret;
}
iso_stream_get_id(s1, &fs_id1, &dev_id1, &ino_id1);
iso_stream_get_id(s2, &fs_id2, &dev_id2, &ino_id2);
if (fs_id1 < fs_id2) {
return -1;
} else if (fs_id1 > fs_id2) {
return 1;
}
/* files belong to the same fs */
if (dev_id1 > dev_id2) {
return -1;
} else if (dev_id1 < dev_id2) {
return 1;
} else if (ino_id1 < ino_id2) {
return -1;
} else if (ino_id1 > ino_id2) {
return 1;
}
size1 = iso_stream_get_size(s1);
size2 = iso_stream_get_size(s2);
if (size1 < size2) {
#ifdef Libisofs_stream_cmp_ino_debuG
if (debug) {
if (report_counter < 5)
fprintf(stderr,
"\n\nlibisofs_DEBUG : Program error: same ino but differing size\n\n\n");
else if (report_counter == 5)
fprintf(stderr,
"\n\nlibisofs_DEBUG : Inode error: more of same ino but differing size\n\n\n");
report_counter++;
}
#endif /* Libisofs_stream_cmp_ino_debuG */
return -1;
} else if (size1 > size2) {
#ifdef Libisofs_stream_cmp_ino_debuG
if (debug) {
if (report_counter < 5)
fprintf(stderr,
"\n\nlibisofs_DEBUG : Inode error: same ino but differing size\n\n\n");
else if (report_counter == 5)
fprintf(stderr,
"\n\nlibisofs_DEBUG : Program error: more of same ino but differing size\n\n\n");
report_counter++;
}
#endif /* Libisofs_stream_cmp_ino_debuG */
return 1;
}
if (s1->class != s2->class)
return (s1->class < s2->class ? -1 : 1);
if (s1->class == &fsrc_stream_class) {
/* Compare eventual image data section LBA and sizes */
fssd1= (FSrcStreamData *) s1->data;
fssd2= (FSrcStreamData *) s2->data;
ret = iso_ifs_sections_cmp(fssd1->src, fssd2->src, 0);
if (ret != 0)
return ret;
}
#ifdef Libisofs_hardlink_matcheR
if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0) {
return (s1 < s2 ? -1 : 1);
}
#endif
return 0;
}

View File

@ -1,8 +1,9 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* Copyright (c) 2009 Thomas Schmitt
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#ifndef LIBISO_STREAM_H_
@ -13,133 +14,73 @@
*/
#include "fsource.h"
/**
* serial number to be used when you can't get a valid id for a Stream by other
* means. If you use this, both fs_id and dev_id should be set to 0.
* This must be incremented each time you get a reference to it.
*/
extern ino_t serial_id;
/*
* Some functions here will be moved to libisofs.h when we expose
* Streams.
*/
typedef struct Iso_Stream IsoStream;
typedef struct IsoStream_Iface
typedef struct
{
/**
* Opens the stream.
*
* @return
* 1 on success, 2 file greater than expected, 3 file smaller than
* expected, < 0 on error
*/
int (*open)(IsoStream *stream);
IsoFileSource *src;
/**
* Close the Stream.
* @return 1 on success, < 0 on error
*/
int (*close)(IsoStream *stream);
/* key for file identification inside filesystem */
dev_t dev_id;
ino_t ino_id;
off_t size; /**< size of this file */
} FSrcStreamData;
/**
* Get the size (in bytes) of the stream. This function should always
* return the same size, even if the underlying source size changes.
*/
off_t (*get_size)(IsoStream *stream);
/**
* Attempts to read up to count bytes from the given stream into
* the buffer starting at buf.
*
* The stream must be open() before calling this, and close() when no
* more needed.
*
* @return
* number of bytes read, 0 if EOF, < 0 on error
*/
int (*read)(IsoStream *stream, void *buf, size_t count);
/**
* Whether this Stram can be read several times, with the same results.
* For example, a regular file is repeatable, you can read it as many
* times as you want. However, a pipe isn't.
*
* This function doesn't take into account if the file has been modified
* between the two reads.
*
* @return
* 1 if stream is repeatable, 0 if not, < 0 on error
*/
int (*is_repeatable)(IsoStream *stream);
/**
* Get an unique identifier for the IsoStream.
*/
void (*get_id)(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
ino_t *ino_id);
/**
* Get a name that identifies the Stream contents. It is used only for
* informational or debug purposes, so you can return anything you
* consider suitable for identification of the source, such as the path.
*/
char *(*get_name)(IsoStream *stream);
/**
* Free implementation specific data. Should never be called by user.
* Use iso_stream_unref() instead.
*/
void (*free)(IsoStream *stream);
} IsoStreamIface;
struct Iso_Stream
{
IsoStreamIface *class;
int refcount;
void *data;
};
void iso_stream_ref(IsoStream *stream);
void iso_stream_unref(IsoStream *stream);
int iso_stream_open(IsoStream *stream);
int iso_stream_close(IsoStream *stream);
off_t iso_stream_get_size(IsoStream *stream);
int iso_stream_read(IsoStream *stream, void *buf, size_t count);
int iso_stream_is_repeatable(IsoStream *stream);
void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
ino_t *ino_id);
char *iso_stream_get_name(IsoStream *stream);
/**
* Get an identifier for the file of the source, for debug purposes
* @param name
* Should provide at least PATH_MAX bytes
*/
void iso_stream_get_file_name(IsoStream *stream, char *name);
/**
* Create a stream to read from a IsoFileSource.
* The stream will take the ref. to the IsoFileSource, so after a successfully
* exectution of this function, you musn't unref() the source, unless you
* take an extra ref.
*
*
* @return
* 1 sucess, < 0 error
* Possible errors:
*
*
*/
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream);
/**
* Create a new stream to read a chunk of an IsoFileSource..
* The stream will add a ref. to the IsoFileSource.
*
* @return
* 1 sucess, < 0 error
*/
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
IsoStream **stream);
/**
* Create a stream for reading from a arbitrary memory buffer.
* When the Stream refcount reach 0, the buffer is free(3).
*
*
* @return
* 1 sucess, < 0 error
*/
int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream);
/**
* Obtain eventual zisofs ZF field entry parameters from a file source out
* of a loaded ISO image.
* To make hope for non-zero reply the stream has to be the original stream
* of an IsoFile with .from_old_session==1. The call is safe with any stream
* type, though, unless fsrc_stream_class would be used without FSrcStreamData.
* @return 1= returned parameters are valid, 0=no ZF info found , <0 error
*/
int iso_stream_get_src_zf(IsoStream *stream, int *header_size_div4,
int *block_size_log2, uint32_t *uncompressed_size,
int flag);
/**
* Set the inode number of a stream that is based on FSrcStreamData, i.e.
* stems from the imported ISO image.
* @return 1 = ok , 0 = not an ISO image stream , <0 = error
*/
int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag);
#endif /*STREAM_H_*/

65
libisofs/system_area.c Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2008 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "system_area.h"
#include "eltorito.h"
#include "filesrc.h"
#include <string.h>
/*
* Create a MBR for an isohybrid enabled ISOLINUX boot image.
*
* It is assumed that the caller has verified the readiness of the boot image
* by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
*
* @param bin_lba The predicted LBA of isolinux.bin within the emerging ISO.
* @param img_blocks The predicted number of 2048 byte blocks in the ISO.
* It will get rounded up to full MBs and that many blocks
* must really be written as ISO 9660 image.
* @param mbr A buffer of at least 512 bytes to take the result which is
* to be written as the very beginning of the ISO.
* @param flag unused yet, submit 0
* @return <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
*/
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
int iso_write_system_area(Ecma119Image *t, uint8_t *buf)
{
if ((t == NULL) || (buf == NULL)) {
return ISO_NULL_POINTER;
}
/* set buf to 0s */
memset(buf, 0, 16 * BLOCK_SIZE);
if (t->catalog != NULL && t->catalog->image->isolinux_options & 0x02) {
/* We need to write a MBR for an hybrid image */
int ret;
int img_blocks;
img_blocks = t->curblock;
ret = make_isohybrid_mbr(t->bootimg->sections[0].block, &img_blocks, (char*)buf, 0);
/*
API description of el_torito_set_isolinux_options() prescribes
to pad to full MB.
So this is not urgent any more :
// FIXME the new img_blocks size should be taken into account
*/
if (ret != 1) {
/* error, it should never happen */
return ISO_ASSERT_FAILURE;
}
}
return ISO_SUCCESS;
}

48
libisofs/system_area.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2008 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/*
* Functions for dealing with the system area, this is, the first 16 blocks
* of the image.
*
* At this time, this is only used for hybrid boot images with isolinux.
*/
#ifndef SYSTEM_AREA_H_
#define SYSTEM_AREA_H_
#include "ecma119.h"
/*
* Create a MBR for an isohybrid enabled ISOLINUX boot image.
*
* It is assumed that the caller has verified the readiness of the boot image
* by checking for 0xfb 0xc0 0x78 0x70 at bytes 0x40 to 0x43 of isolinux.bin.
*
* @param bin_lba The predicted LBA of isolinux.bin within the emerging ISO.
* @param img_blocks The predicted number of 2048 byte blocks in the ISO.
* It will get rounded up to full MBs and that many blocks
* must really be written as ISO 9660 image.
* @param mbr A buffer of at least 512 bytes to take the result which is
* to be written as the very beginning of the ISO.
* @param flag unused yet, submit 0
* @return <0 = fatal, 0 = failed , 1 = ok , 2 = ok with size warning
*/
int make_isohybrid_mbr(int bin_lba, int *img_blocks, char *mbr, int flag);
/**
* Write the system area for the given image to the given buffer.
*
* @param buf
* A buffer with at least 32 K allocated
* @return
* 1 if success, < 0 on error
*/
int iso_write_system_area(Ecma119Image *t, uint8_t *buf);
#endif /* SYSTEM_AREA_H_ */

View File

@ -256,6 +256,81 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/**
* Add a new regular file to the iso tree. Permissions are set to 0444,
* owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new file will be created
* @param name
* name for the new file. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param stream
* IsoStream for the contents of the file
* @param file
* place where to store a pointer to the newly created file. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/
int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream,
IsoFile **file)
{
int ret;
char *n;
IsoFile *node;
IsoNode **pos;
time_t now;
if (parent == NULL || name == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (file) {
*file = NULL;
}
/* find place where to insert */
if (iso_dir_exists(parent, name, &pos)) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
n = strdup(name);
ret = iso_node_new_file(n, stream, &node);
if (ret < 0) {
free(n);
return ret;
}
/* permissions from parent */
iso_node_set_permissions((IsoNode*)node, 0444);
iso_node_set_uid((IsoNode*)node, parent->node.uid);
iso_node_set_gid((IsoNode*)node, parent->node.gid);
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
/* current time */
now = time(NULL);
iso_node_set_atime((IsoNode*)node, now);
iso_node_set_ctime((IsoNode*)node, now);
iso_node_set_mtime((IsoNode*)node, now);
if (file) {
*file = node;
}
/* add to dir */
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/**
* Set whether to follow or not symbolic links when added a file from a source
* to IsoImage.
@ -475,6 +550,139 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
return result;
}
int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
const char *path, IsoNode **node)
{
int result;
IsoFilesystem *fs;
IsoFileSource *file;
IsoNode *new;
IsoNode **pos;
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
if (node) {
*node = NULL;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &file);
if (result < 0) {
return result;
}
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
iso_file_source_unref(file);
return ISO_NODE_NAME_NOT_UNIQUE;
}
result = image->builder->create_node(image->builder, image, file, &new);
/* free the file */
iso_file_source_unref(file);
if (result < 0) {
return result;
}
result = iso_node_set_name(new, name);
if (result < 0) {
iso_node_unref(new);
return result;
}
if (node) {
*node = new;
}
/* finally, add node to parent */
return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER);
}
int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent,
const char *name, const char *path,
off_t offset, off_t size,
IsoNode **node)
{
int result;
struct stat info;
IsoFilesystem *fs;
IsoFileSource *src;
IsoFile *new;
IsoNode **pos;
IsoStream *stream;
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
if (node) {
*node = NULL;
}
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &src);
if (result < 0) {
return result;
}
result = iso_file_source_stat(src, &info);
if (result < 0) {
iso_file_source_unref(src);
return result;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset >= info.st_size) {
return ISO_WRONG_ARG_VALUE;
}
/* force regular file */
result = image->builder->create_file(image->builder, image, src, &new);
/* free the file */
iso_file_source_unref(src);
if (result < 0) {
return result;
}
/* replace file iso stream with a cut-out-stream */
result = iso_cut_out_stream_new(src, offset, size, &stream);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
iso_stream_unref(new->stream);
new->stream = stream;
result = iso_node_set_name((IsoNode*)new, name);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
if (node) {
*node = (IsoNode*)new;
}
/* finally, add node to parent */
return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
}
static
int check_excludes(IsoImage *image, const char *path)
{
@ -730,6 +938,7 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
while (component) {
if (n->type != LIBISO_DIR) {
n = NULL;
result = 0;
break;
}
dir = (IsoDir *)n;
@ -749,3 +958,27 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
}
return result;
}
char *iso_tree_get_node_path(IsoNode *node)
{
if (node == NULL || node->parent == NULL) {
return NULL;
}
if ((IsoNode*)node->parent == node) {
return strdup("/");
} else {
char path[PATH_MAX];
char *parent_path = iso_tree_get_node_path((IsoNode*)node->parent);
if (parent_path == NULL) {
return NULL;
}
if (strlen(parent_path) == 1) {
snprintf(path, PATH_MAX, "/%s", node->name);
} else {
snprintf(path, PATH_MAX, "%s/%s", parent_path, node->name);
}
free(parent_path);
return strdup(path);
}
}

View File

@ -13,24 +13,132 @@
#include <stdlib.h>
#include <wchar.h>
#include <iconv.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <limits.h>
#include <iconv.h>
#include <locale.h>
#include <langinfo.h>
#include <unistd.h>
/* if we don't have eaccess, we check file access by openning it */
/* if we don't have eaccess, we check file access by opening it */
#ifndef HAVE_EACCESS
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
/* Produce possibly inflationary error messages directly to stderr */
static int iso_iconv_debug = 0;
struct iso_iconv_handle {
int status; /* bit0= open , bit1= identical mapping */
iconv_t descr;
};
/*
@param flag bit0= shortcut by identical mapping is not allowed
*/
static
int iso_iconv_open(struct iso_iconv_handle *handle,
char *tocode, char *fromcode, int flag)
{
handle->status = 0;
handle->descr = (iconv_t) -1;
if (strcmp(tocode, fromcode) == 0 && !(flag & 1)) {
handle->status = 1 | 2;
return 1;
}
handle->descr = iconv_open(tocode, fromcode);
if (handle->descr == (iconv_t) -1) {
if (strlen(tocode) + strlen(fromcode) <= 160 && iso_iconv_debug)
fprintf(stderr,
"libisofs_DEBUG: iconv_open(\"%s\", \"%s\") failed: errno= %d %s\n",
tocode, fromcode, errno, strerror(errno));
return 0;
}
handle->status = 1;
return 1;
}
static
size_t iso_iconv(struct iso_iconv_handle *handle,
char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft, int flag)
{
size_t ret;
if (!(handle->status & 1)) {
if (iso_iconv_debug)
fprintf(stderr,
"libisofs_DEBUG: iso_iconv(): iso_iconv_handle not in open state\n");
return (size_t) -1;
}
if (handle->status & 2) {
if (inbuf == NULL || outbuf == NULL) {
null_buf:;
if (iso_iconv_debug)
fprintf(stderr,
"libisofs_DEBUG: iso_iconv(): NULL buffers not allowed in shortcut mapping\n");
return (size_t) -1;
}
if (*inbuf == NULL || *outbuf == NULL)
goto null_buf;
while (*inbytesleft > 0 && *outbytesleft > 0) {
*((*outbuf)++) = *((*inbuf)++);
(*inbytesleft)--;
(*outbytesleft)--;
}
if (*inbytesleft > 0 && *outbytesleft <= 0)
return (size_t) -1;
return (size_t) 0;
}
ret = iconv(handle->descr, inbuf, inbytesleft, outbuf, outbytesleft);
if (ret == (size_t) -1) {
if (iso_iconv_debug)
fprintf(stderr, "libisofs_DEBUG: iconv() failed: errno= %d %s\n",
errno, strerror(errno));
return (size_t) -1;
}
return ret;
}
static
int iso_iconv_close(struct iso_iconv_handle *handle, int flag)
{
int ret;
if (!(handle->status & 1)) {
if (iso_iconv_debug)
fprintf(stderr,
"libisofs_DEBUG: iso_iconv_close(): iso_iconv_handle not in open state\n");
return -1;
}
handle->status &= ~1;
if (handle->status & 2)
return 0;
ret = iconv_close(handle->descr);
if (ret == -1) {
if (iso_iconv_debug)
fprintf(stderr,
"libisofs_DEBUG: iconv_close() failed: errno= %d %s\n",
errno, strerror(errno));
return -1;
}
return ret;
}
int int_pow(int base, int power)
{
int result = 1;
@ -40,46 +148,80 @@ int int_pow(int base, int power)
return result;
}
/* This static variable can override the locale's charset by its getter
function which should be used whenever the local character set name
is to be inquired. I.e. instead of calling nl_langinfo(CODESET) directly.
If the variable is empty then it forwards nl_langinfo(CODESET).
*/
static char libisofs_local_charset[4096]= {""};
/* API function */
int iso_set_local_charset(char *name, int flag)
{
if(strlen(name) >= sizeof(libisofs_local_charset))
return(0);
strcpy(libisofs_local_charset, name);
return 1;
}
/* API function */
char *iso_get_local_charset(int flag)
{
if(libisofs_local_charset[0])
return libisofs_local_charset;
return nl_langinfo(CODESET);
}
int strconv(const char *str, const char *icharset, const char *ocharset,
char **output)
{
size_t inbytes;
size_t outbytes;
size_t n;
iconv_t conv;
char *out;
struct iso_iconv_handle conv;
int conv_ret;
char *out = NULL;
char *src;
char *ret;
int retval;
inbytes = strlen(str);
outbytes = (inbytes + 1) * MB_LEN_MAX;
out = alloca(outbytes);
out = calloc(outbytes, 1);
if (out == NULL) {
return ISO_OUT_OF_MEM;
retval = ISO_OUT_OF_MEM;
goto ex;
}
conv = iconv_open(ocharset, icharset);
if (conv == (iconv_t)(-1)) {
return ISO_CHARSET_CONV_ERROR;
conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
if (conv_ret <= 0) {
retval = ISO_CHARSET_CONV_ERROR;
goto ex;
}
src = (char *)str;
ret = (char *)out;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
if (n == -1) {
/* error */
iconv_close(conv);
return ISO_CHARSET_CONV_ERROR;
iso_iconv_close(&conv, 0);
retval = ISO_CHARSET_CONV_ERROR;
goto ex;
}
*ret = '\0';
iconv_close(conv);
iso_iconv_close(&conv, 0);
*output = malloc(ret - out + 1);
if (*output == NULL) {
return ISO_OUT_OF_MEM;
retval = ISO_OUT_OF_MEM;
goto ex;
}
memcpy(*output, out, ret - out + 1);
return ISO_SUCCESS;
retval = ISO_SUCCESS;
ex:;
if (out != NULL)
free(out);
return retval;
}
int strnconv(const char *str, const char *icharset, const char *ocharset,
@ -88,40 +230,48 @@ int strnconv(const char *str, const char *icharset, const char *ocharset,
size_t inbytes;
size_t outbytes;
size_t n;
iconv_t conv;
char *out;
struct iso_iconv_handle conv;
int conv_ret;
char *out = NULL;
char *src;
char *ret;
int retval;
inbytes = len;
outbytes = (inbytes + 1) * MB_LEN_MAX;
out = alloca(outbytes);
out = calloc(outbytes, 1);
if (out == NULL) {
return ISO_OUT_OF_MEM;
retval = ISO_OUT_OF_MEM;
goto ex;
}
conv = iconv_open(ocharset, icharset);
if (conv == (iconv_t)(-1)) {
return ISO_CHARSET_CONV_ERROR;
conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
if (conv_ret <= 0) {
retval = ISO_CHARSET_CONV_ERROR;
goto ex;
}
src = (char *)str;
ret = (char *)out;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
if (n == -1) {
/* error */
iconv_close(conv);
return ISO_CHARSET_CONV_ERROR;
iso_iconv_close(&conv, 0);
retval = ISO_CHARSET_CONV_ERROR;
goto ex;
}
*ret = '\0';
iconv_close(conv);
iso_iconv_close(&conv, 0);
*output = malloc(ret - out + 1);
if (*output == NULL) {
return ISO_OUT_OF_MEM;
retval = ISO_OUT_OF_MEM;
goto ex;
}
memcpy(*output, out, ret - out + 1);
return ISO_SUCCESS;
retval = ISO_SUCCESS;
ex:;
if (out != NULL)
free(out);
return retval;
}
/**
@ -134,7 +284,12 @@ int strnconv(const char *str, const char *icharset, const char *ocharset,
static
int str2wchar(const char *icharset, const char *input, wchar_t **output)
{
iconv_t conv;
struct iso_iconv_handle conv;
int conv_ret;
/* That while loop smells like a potential show stopper */
size_t loop_counter = 0, loop_limit = 3;
size_t inbytes;
size_t outbytes;
char *ret;
@ -146,12 +301,13 @@ int str2wchar(const char *icharset, const char *input, wchar_t **output)
return ISO_NULL_POINTER;
}
conv = iconv_open("WCHAR_T", icharset);
if (conv == (iconv_t)-1) {
conv_ret = iso_iconv_open(&conv, "WCHAR_T", (char *) icharset, 0);
if (conv_ret <= 0) {
return ISO_CHARSET_CONV_ERROR;
}
inbytes = strlen(input);
loop_limit = inbytes + 3;
outbytes = (inbytes + 1) * sizeof(wchar_t);
/* we are sure that numchars <= inbytes */
@ -162,14 +318,12 @@ int str2wchar(const char *icharset, const char *input, wchar_t **output)
ret = (char *)wstr;
src = (char *)input;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
while (n == -1) {
if (errno == E2BIG) {
/* error, should never occur */
iconv_close(conv);
free(wstr);
return ISO_CHARSET_CONV_ERROR;
goto conv_error;
} else {
wchar_t *wret;
@ -189,14 +343,23 @@ int str2wchar(const char *icharset, const char *input, wchar_t **output)
if (!inbytes)
break;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
/* Just to appease my remorse about unclear loop ends */
loop_counter++;
if (loop_counter > loop_limit)
goto conv_error;
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
}
}
iconv_close(conv);
iso_iconv_close(&conv, 0);
*( (wchar_t *)ret )='\0';
*output = wstr;
return ISO_SUCCESS;
conv_error:;
iso_iconv_close(&conv, 0);
free(wstr);
return ISO_CHARSET_CONV_ERROR;
}
int str2ascii(const char *icharset, const char *input, char **output)
@ -206,12 +369,21 @@ int str2ascii(const char *icharset, const char *input, char **output)
char *ret;
char *ret_;
char *src;
iconv_t conv;
struct iso_iconv_handle conv;
int conv_ret;
/* That while loop smells like a potential show stopper */
size_t loop_counter = 0, loop_limit = 3;
/* Fallback in case that iconv() is too demanding for system */
unsigned char *cpt;
size_t numchars;
size_t outbytes;
size_t inbytes;
size_t n;
if (icharset == NULL || input == NULL || output == NULL) {
return ISO_NULL_POINTER;
}
@ -222,12 +394,13 @@ int str2ascii(const char *icharset, const char *input, char **output)
*/
result = str2wchar(icharset, input, &wsrc_);
if (result < 0) {
return result;
goto fallback;
}
src = (char *)wsrc_;
numchars = wcslen(wsrc_);
inbytes = numchars * sizeof(wchar_t);
loop_limit = inbytes + 3;
ret_ = malloc(numchars + 1);
if (ret_ == NULL) {
@ -237,14 +410,14 @@ int str2ascii(const char *icharset, const char *input, char **output)
ret = ret_;
/* initialize iconv */
conv = iconv_open("ASCII", "WCHAR_T");
if (conv == (iconv_t)-1) {
conv_ret = iso_iconv_open(&conv, "ASCII", "WCHAR_T", 0);
if (conv_ret <= 0) {
free(wsrc_);
free(ret_);
return ISO_CHARSET_CONV_ERROR;
goto fallback;
}
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
while (n == -1) {
/* The destination buffer is too small. Stops here. */
if (errno == E2BIG)
@ -274,16 +447,29 @@ int str2ascii(const char *icharset, const char *input, char **output)
if (!inbytes)
break;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
/* Just to appease my remorse about unclear loop ends */
loop_counter++;
if (loop_counter > loop_limit)
break;
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
}
iconv_close(conv);
iso_iconv_close(&conv, 0);
*ret='\0';
free(wsrc_);
*output = ret_;
return ISO_SUCCESS;
fallback:;
/* Assume to have a single byte charset with ASCII as core.
Anything suspicious will be mapped to '_'.
*/
*output = strdup(input);
for (cpt = (unsigned char *) *output; *cpt; cpt++) {
if (*cpt < 32 || *cpt > 126)
*cpt = '_';
}
return ISO_SUCCESS;
}
static
@ -318,7 +504,12 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
char *src;
char *ret;
char *ret_;
iconv_t conv;
struct iso_iconv_handle conv;
int conv_ret;
/* That while loop smells like a potential show stopper */
size_t loop_counter = 0, loop_limit = 3;
size_t numchars;
size_t outbytes;
size_t inbytes;
@ -340,6 +531,7 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
numchars = wcslen(wsrc_);
inbytes = numchars * sizeof(wchar_t);
loop_limit = inbytes + 3;
ret_ = malloc((numchars+1) * sizeof(uint16_t));
if (ret_ == NULL) {
@ -349,14 +541,14 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
ret = ret_;
/* initialize iconv */
conv = iconv_open("UCS-2BE", "WCHAR_T");
if (conv == (iconv_t)-1) {
conv_ret = iso_iconv_open(&conv, "UCS-2BE", "WCHAR_T", 0);
if (conv_ret <= 0) {
free(wsrc_);
free(ret_);
return ISO_CHARSET_CONV_ERROR;
}
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
while (n == -1) {
/* The destination buffer is too small. Stops here. */
if (errno == E2BIG)
@ -386,10 +578,13 @@ int str2ucs(const char *icharset, const char *input, uint16_t **output)
if (!inbytes)
break;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
/* Just to appease my remorse about unclear loop ends */
loop_counter++;
if (loop_counter > loop_limit)
break;
n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
}
iconv_close(conv);
iso_iconv_close(&conv, 0);
/* close the ucs string */
set_ucsbe((uint16_t*) ret, '\0');
@ -602,12 +797,16 @@ char *iso_r_dirid(const char *src, int size, int relaxed)
*/
char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
{
char *dot;
char *dot, *retval = NULL;
int lname, lext, lnname, lnext, pos, i;
char *dest = alloca(len + 1 + 1);
char *dest = NULL;
dest = calloc(len + 1 + 1, 1);
if (dest == NULL)
goto ex;
if (src == NULL) {
return NULL;
goto ex;
}
dot = strrchr(src, '.');
@ -632,7 +831,7 @@ char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
}
if (lnname == 0 && lnext == 0) {
return NULL;
goto ex;
}
pos = 0;
@ -688,7 +887,13 @@ char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
}
}
dest[pos] = '\0';
return strdup(dest);
retval = strdup(dest);
ex:;
if (dest != NULL)
free(dest);
return retval;
}
uint16_t *iso_j_file_id(const uint16_t *src)
@ -1207,8 +1412,9 @@ void strncpy_pad(char *dest, const char *src, size_t max)
char *ucs2str(const char *buf, size_t len)
{
size_t outbytes, inbytes;
char *str, *src, *out;
iconv_t conv;
char *str, *src, *out = NULL, *retval = NULL;
struct iso_iconv_handle conv;
int conv_ret;
size_t n;
inbytes = len;
@ -1216,30 +1422,34 @@ char *ucs2str(const char *buf, size_t len)
outbytes = (inbytes+1) * MB_LEN_MAX;
/* ensure enought space */
out = alloca(outbytes);
out = calloc(outbytes, 1);
/* convert to local charset */
setlocale(LC_CTYPE, "");
conv = iconv_open(nl_langinfo(CODESET), "UCS-2BE");
if (conv == (iconv_t)(-1)) {
return NULL;
conv_ret = iso_iconv_open(&conv, iso_get_local_charset(0), "UCS-2BE", 0);
if (conv_ret <= 0) {
goto ex;
}
src = (char *)buf;
str = (char *)out;
n = iconv(conv, &src, &inbytes, &str, &outbytes);
n = iso_iconv(&conv, &src, &inbytes, &str, &outbytes, 0);
iso_iconv_close(&conv, 0);
if (n == -1) {
/* error */
iconv_close(conv);
return NULL;
goto ex;
}
iconv_close(conv);
*str = '\0';
/* remove trailing spaces */
for (len = strlen(out) - 1; out[len] == ' ' && len > 0; --len)
out[len] = '\0';
return strdup(out);
retval = strdup(out);
ex:;
if (out != NULL)
free(out);
return retval;
}
void iso_lib_version(int *major, int *minor, int *micro)
@ -1262,3 +1472,11 @@ int iso_lib_is_compatible(int major, int minor, int micro)
&& (cminor > minor
|| (cminor == minor && cmicro >= micro)));
}
int iso_init_locale(int flag)
{
setlocale(LC_CTYPE, "");
return 1;
}

View File

@ -25,6 +25,11 @@
int int_pow(int base, int power);
/**
* Set up locale by LC_* environment variables.
*/
int iso_init_locale(int flag);
/**
* Convert the charset encoding of a given string.
*

View File

@ -198,7 +198,11 @@ int iso_rbtree_insert(IsoRBTree *tree, void *data, void **item)
}
}
comp = tree->compare(q->data, data);
if (q->data == data) {
comp = 0;
} else {
comp = tree->compare(q->data, data);
}
/* Stop if found */
if (comp == 0) {

View File

@ -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);
}

View File

@ -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);

View 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);
}