Writing ZF entries if filters and image generation mode indicate so.

This commit is contained in:
Thomas Schmitt 2009-04-10 22:38:16 +02:00
parent ce7a5c810f
commit 540df15ec9
3 changed files with 237 additions and 52 deletions

View File

@ -90,7 +90,7 @@ Its fields are:
ISO 9660:7.1.1. ISO 9660:7.1.1.
(This is a copy of header byte 13, resp. header BP 14.) (This is a copy of header byte 13, resp. header BP 14.)
Implementations shall be able to handle values 15, 16 and 17 i.e. Implementations shall be able to handle values 15, 16 and 17 i.e.
block sizes 32 kB, 64 kB, and 128 kB. block sizes 32 kiB, 64 kiB, and 128 kiB.
[7] "BP 9 to BP 16 - Uncompressed Size" shall tell the number of uncompressed [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 bytes represented by the given extent. This field shall be recorded
@ -103,8 +103,8 @@ Its fields are:
ISO 9660:7.3.3 means 4-byte word in both byte orders, first little endian, then ISO 9660:7.3.3 means 4-byte word in both byte orders, first little endian, then
big endian. big endian.
Example (block size 32 kB, uncompressed file size = 1,234,567 bytes): Example (block size 32 kiB, uncompressed file size = 1,234,567 bytes):
{ 'Z', "F', 16, 1, 'p', 'z', 16, 15, { 'Z', "F', 16, 1, 'p', 'z', 4, 15,
0x87, 0xD6, 0x12, 0x00, 0x00, 0x12, 0xD6, 0x87 } 0x87, 0xD6, 0x12, 0x00, 0x00, 0x12, 0xD6, 0x87 }
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -112,10 +112,8 @@ Revoked specification aspects:
The comments in zisofs-tools-1.0.8 indicate a special case of output block: The comments in zisofs-tools-1.0.8 indicate a special case of output block:
"a block the length of which is equal to the block size is unencoded." "a block the length of which is equal to the block size is unencoded."
This was not implemented in zisofs-tools and in the Linux kernel. It has to This is not implemented in zisofs-tools and in the Linux kernel.
be doubted that it can be added to the existing reader implementations in an Therefore that rule is not part of this description and must not be
unambigous way.
Therefore that rule is not part of this description and shall not be
implemented. implemented.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------

View File

@ -51,10 +51,14 @@
typedef struct typedef struct
{ {
int state; /* processing: 0= header, 1= block pointers, 2= data blocks */ int state; /* processing: 0= header, 1= block pointers, 2= data blocks */
int block_size;
int block_size;
int block_pointer_fill; int block_pointer_fill;
int block_pointer_rpos; int block_pointer_rpos;
uint32_t *block_pointers; /* These are in use only with uncompression.
Compression streams hold the pointer in
their persistent data.
*/
char *read_buffer; char *read_buffer;
char *block_buffer; char *block_buffer;
@ -77,6 +81,8 @@ int ziso_running_destroy(ZisofsFilterRuntime **running, int flag)
ZisofsFilterRuntime *o= *running; ZisofsFilterRuntime *o= *running;
if (o == NULL) if (o == NULL)
return 0; return 0;
if (o->block_pointers != NULL)
free(o->block_pointers);
if (o->read_buffer != NULL) if (o->read_buffer != NULL)
free(o->read_buffer); free(o->read_buffer);
if (o->block_buffer != NULL) if (o->block_buffer != NULL)
@ -99,9 +105,10 @@ int ziso_running_new(ZisofsFilterRuntime **running, int flag)
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
} }
o->state = 0; o->state = 0;
o->block_size= 0;
o->block_pointer_fill = 0; o->block_pointer_fill = 0;
o->block_pointer_rpos = 0; o->block_pointer_rpos = 0;
o->block_size= 0; o->block_pointers = NULL;
o->read_buffer = NULL; o->read_buffer = NULL;
o->block_buffer = NULL; o->block_buffer = NULL;
o->buffer_size = 0; o->buffer_size = 0;
@ -140,25 +147,47 @@ static unsigned char zisofs_magic[9] =
/* /*
* The data payload of an individual Zisofs Filter IsoStream * The common data payload of an individual Zisofs Filter IsoStream
*/ */
typedef struct typedef struct
{ {
ino_t id;
IsoStream *orig; IsoStream *orig;
off_t size; /* -1 means that the size is unknown yet */ off_t size; /* -1 means that the size is unknown yet */
ZisofsFilterRuntime *running; /* is non-NULL when open */
ino_t id;
} ZisofsFilterStreamData;
/*
* The data payload of an individual Zisofs Filter Compressor IsoStream
*/
typedef struct
{
ZisofsFilterStreamData std;
uint32_t orig_size; uint32_t orig_size;
uint32_t *block_pointers; /* Cache for output block addresses. They get uint32_t *block_pointers; /* Cache for output block addresses. They get
written before the data and so need 2 passes. written before the data and so need 2 passes.
This cache avoids surplus passes. This cache avoids surplus passes.
*/ */
} ZisofsComprStreamData;
ZisofsFilterRuntime *running; /* is non-NULL when open */
} ZisofsFilterStreamData; /*
* The data payload of an individual Zisofs Filter Uncompressor IsoStream
*/
typedef struct
{
ZisofsFilterStreamData std;
unsigned char header_size_div4;
unsigned char block_size_log2;
} ZisofsUncomprStreamData;
/* Each individual ZisofsFilterStreamData needs a unique id number. */ /* Each individual ZisofsFilterStreamData needs a unique id number. */
@ -194,13 +223,6 @@ int ziso_stream_close_flag(IsoStream *stream, int flag)
ziso_running_destroy(&(data->running), 0); ziso_running_destroy(&(data->running), 0);
if (flag & 1) if (flag & 1)
return 1; return 1;
if (stream->class->read == ziso_stream_uncompress &&
data->block_pointers != NULL) {
/* No permanent block pointers needed for uncompression */
free(data->block_pointers);
data->block_pointers = NULL;
}
return iso_stream_close(data->orig); return iso_stream_close(data->orig);
} }
@ -237,7 +259,7 @@ int ziso_stream_open_flag(IsoStream *stream, int flag)
} }
ret = ziso_running_new(&running, ret = ziso_running_new(&running,
stream->class->read == ziso_stream_uncompress); stream->class->read == &ziso_stream_uncompress);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -265,7 +287,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
#ifdef Libisofs_with_zliB #ifdef Libisofs_with_zliB
int ret, todo, i; int ret, todo, i;
ZisofsFilterStreamData *data; ZisofsComprStreamData *data;
ZisofsFilterRuntime *rng; ZisofsFilterRuntime *rng;
size_t fill = 0; size_t fill = 0;
off_t orig_size, next_pt; off_t orig_size, next_pt;
@ -276,7 +298,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
data = stream->data; data = stream->data;
rng= data->running; rng= data->std.running;
if (rng == NULL) { if (rng == NULL) {
return ISO_FILE_NOT_OPENED; return ISO_FILE_NOT_OPENED;
} }
@ -290,7 +312,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
if (rng->buffer_fill == 0) { if (rng->buffer_fill == 0) {
memcpy(rng->block_buffer, zisofs_magic, 8); memcpy(rng->block_buffer, zisofs_magic, 8);
orig_size = iso_stream_get_size(data->orig); orig_size = iso_stream_get_size(data->std.orig);
if (orig_size > 4294967295.0) { if (orig_size > 4294967295.0) {
return (rng->error_ret = ISO_ZISOFS_TOO_LARGE); return (rng->error_ret = ISO_ZISOFS_TOO_LARGE);
} }
@ -347,7 +369,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
if (rng->state == 2 && rng->buffer_rpos >= rng->buffer_fill) { if (rng->state == 2 && rng->buffer_rpos >= rng->buffer_fill) {
/* Delivering data blocks */; /* Delivering data blocks */;
ret = iso_stream_read(data->orig, rng->read_buffer, ret = iso_stream_read(data->std.orig, rng->read_buffer,
rng->block_size); rng->block_size);
if (ret > 0) { if (ret > 0) {
rng->in_counter += ret; rng->in_counter += ret;
@ -374,7 +396,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired)
next_pt = data->block_pointers[rng->block_counter] + buf_len; next_pt = data->block_pointers[rng->block_counter] + buf_len;
if (data->size >= 0 && next_pt > data->size) { if (data->std.size >= 0 && next_pt > data->std.size) {
/* Compression yields more bytes than on first run */ /* Compression yields more bytes than on first run */
return (rng->error_ret = ISO_FILTER_WRONG_INPUT); return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
} }
@ -443,6 +465,7 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
int ret, todo, i, header_size, bs_log2, block_max = 1; int ret, todo, i, header_size, bs_log2, block_max = 1;
ZisofsFilterStreamData *data; ZisofsFilterStreamData *data;
ZisofsFilterRuntime *rng; ZisofsFilterRuntime *rng;
ZisofsUncomprStreamData *nstd;
size_t fill = 0; size_t fill = 0;
char *cbuf = buf; char *cbuf = buf;
uLongf buf_len; uLongf buf_len;
@ -452,6 +475,7 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
} }
data = stream->data; data = stream->data;
nstd = stream->data;
rng= data->running; rng= data->running;
if (rng == NULL) { if (rng == NULL) {
return ISO_FILE_NOT_OPENED; return ISO_FILE_NOT_OPENED;
@ -482,6 +506,8 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT); return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT);
} }
data->size = iso_read_lsb(((uint8_t *) zisofs_head) + 8, 4); data->size = iso_read_lsb(((uint8_t *) zisofs_head) + 8, 4);
nstd->header_size_div4 = header_size / 4;
nstd->block_size_log2 = bs_log2;
if (desired == 0) { if (desired == 0) {
return 0; return 0;
@ -491,25 +517,25 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
rng->block_pointer_rpos = 0; rng->block_pointer_rpos = 0;
rng->block_pointer_fill = data->size / rng->block_size rng->block_pointer_fill = data->size / rng->block_size
+ 1 + !!(data->size % rng->block_size); + 1 + !!(data->size % rng->block_size);
data->block_pointers = calloc(rng->block_pointer_fill, 4); rng->block_pointers = calloc(rng->block_pointer_fill, 4);
if (data->block_pointers == NULL) { if (rng->block_pointers == NULL) {
rng->block_pointer_fill = 0; rng->block_pointer_fill = 0;
return (rng->error_ret = ISO_OUT_OF_MEM); return (rng->error_ret = ISO_OUT_OF_MEM);
} }
ret = iso_stream_read(data->orig, data->block_pointers, ret = iso_stream_read(data->orig, rng->block_pointers,
rng->block_pointer_fill * 4); rng->block_pointer_fill * 4);
if (ret < 0) if (ret < 0)
return (rng->error_ret = ret); return (rng->error_ret = ret);
if (ret != rng->block_pointer_fill * 4) if (ret != rng->block_pointer_fill * 4)
return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT); return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT);
for (i = 0; i < rng->block_pointer_fill; i++) { for (i = 0; i < rng->block_pointer_fill; i++) {
data->block_pointers[i] = rng->block_pointers[i] =
iso_read_lsb((uint8_t *) (data->block_pointers + i), 4); iso_read_lsb((uint8_t *) (rng->block_pointers + i), 4);
if (i > 0) if (i > 0)
if (data->block_pointers[i] - data->block_pointers[i - 1] if (rng->block_pointers[i] - rng->block_pointers[i - 1]
> block_max) > block_max)
block_max = data->block_pointers[i] block_max = rng->block_pointers[i]
- data->block_pointers[i - 1]; - rng->block_pointers[i - 1];
} }
rng->read_buffer = calloc(block_max, 1); rng->read_buffer = calloc(block_max, 1);
@ -527,9 +553,9 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired)
/* More data blocks than announced */ /* More data blocks than announced */
return (rng->error_ret = ISO_FILTER_WRONG_INPUT); return (rng->error_ret = ISO_FILTER_WRONG_INPUT);
} }
todo = data->block_pointers[i] - data->block_pointers[i- 1]; todo = rng->block_pointers[i] - rng->block_pointers[i- 1];
if (todo == 0) { if (todo == 0) {
memset(rng->read_buffer, 0, rng->block_size); memset(rng->block_buffer, 0, rng->block_size);
rng->buffer_fill = rng->block_size; rng->buffer_fill = rng->block_size;
if (rng->in_counter + rng->buffer_fill > data->size && if (rng->in_counter + rng->buffer_fill > data->size &&
i == rng->block_pointer_fill - 1) i == rng->block_pointer_fill - 1)
@ -616,7 +642,7 @@ off_t ziso_stream_get_size(IsoStream *stream)
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
if (stream->class->read == ziso_stream_uncompress) { if (stream->class->read == &ziso_stream_uncompress) {
/* It is enough to read the header part of a compressed file */ /* It is enough to read the header part of a compressed file */
ret = ziso_stream_uncompress(stream, buf, 0); ret = ziso_stream_uncompress(stream, buf, 0);
count = data->size; count = data->size;
@ -673,8 +699,11 @@ void ziso_stream_free(IsoStream *stream)
if (data->running != NULL) { if (data->running != NULL) {
ziso_stream_close(stream); ziso_stream_close(stream);
} }
if (data->block_pointers != NULL) { if (stream->class->read != &ziso_stream_uncompress) {
free((char *) data->block_pointers); ZisofsComprStreamData *nstd;
nstd = stream->data;
if (nstd->block_pointers != NULL)
free((char *) nstd->block_pointers);
} }
iso_stream_unref(data->orig); iso_stream_unref(data->orig);
free(data); free(data);
@ -748,6 +777,8 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original,
{ {
IsoStream *str; IsoStream *str;
ZisofsFilterStreamData *data; ZisofsFilterStreamData *data;
ZisofsComprStreamData *cnstd;
ZisofsUncomprStreamData *unstd;
if (filter == NULL || original == NULL || filtered == NULL) { if (filter == NULL || original == NULL || filtered == NULL) {
return ISO_NULL_POINTER; return ISO_NULL_POINTER;
@ -757,7 +788,13 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original,
if (str == NULL) { if (str == NULL) {
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
} }
data = calloc(sizeof(ZisofsFilterStreamData), 1); if (flag & 2) {
unstd = calloc(sizeof(ZisofsUncomprStreamData), 1);
data = (ZisofsFilterStreamData *) unstd;
} else {
cnstd = calloc(sizeof(ZisofsComprStreamData), 1);
data = (ZisofsFilterStreamData *) cnstd;
}
if (data == NULL) { if (data == NULL) {
free(str); free(str);
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
@ -767,8 +804,6 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original,
data->id = ++ziso_ino_id; data->id = ++ziso_ino_id;
data->orig = original; data->orig = original;
data->size = -1; data->size = -1;
data->orig_size = 0;
data->block_pointers = NULL;
data->running = NULL; data->running = NULL;
/* get reference to the source */ /* get reference to the source */
@ -777,8 +812,12 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original,
str->refcount = 1; str->refcount = 1;
str->data = data; str->data = data;
if (flag & 2) { if (flag & 2) {
unstd->header_size_div4 = 0;
unstd->block_size_log2 = 0;
str->class = &ziso_stream_uncompress_class; str->class = &ziso_stream_uncompress_class;
} else { } else {
cnstd->orig_size = 0;
cnstd->block_pointers = NULL;
str->class = &ziso_stream_compress_class; str->class = &ziso_stream_compress_class;
} }
@ -878,8 +917,9 @@ int iso_file_add_zisofs_filter(IsoFile *file, int flag)
iso_file_remove_filter(file, 0); iso_file_remove_filter(file, 0);
return filtered_size; return filtered_size;
} }
if (((filtered_size >= original_size && !(flag & 1)) || if ((filtered_size >= original_size ||
filtered_size / 2048 >= original_size / 2048) && !(flag & 2)){ ((flag & 1) && filtered_size / 2048 >= original_size / 2048))
&& !(flag & 2)){
ret = iso_file_remove_filter(file, 0); ret = iso_file_remove_filter(file, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -897,3 +937,34 @@ int iso_file_add_zisofs_filter(IsoFile *file, int flag)
} }
/* Determine stream type : 1=ziso , -1=osiz , 0=other
and eventual ZF field parameters
*/
int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type,
int *header_size_div4, int *block_size_log2,
uint32_t *uncompressed_size, int flag)
{
ZisofsFilterStreamData *data;
ZisofsComprStreamData *cnstd;
ZisofsUncomprStreamData *unstd;
*stream_type = 0;
if (stream->class == &ziso_stream_compress_class) {
*stream_type = 1;
cnstd = stream->data;
*header_size_div4 = 4;
*block_size_log2 = Libisofs_zisofs_block_log2;
*uncompressed_size = cnstd->orig_size;
return 1;
} else if(stream->class == &ziso_stream_uncompress_class) {
*stream_type = -1;
data = stream->data;
unstd = stream->data;
*header_size_div4 = unstd->header_size_div4;
*block_size_log2 = unstd->block_size_log2;
*uncompressed_size = data->size;
return 1;
}
return 0;
}

View File

@ -767,6 +767,109 @@ int susp_add_ES(Ecma119Image *t, struct susp_info *susp, int to_ce, int seqno)
} }
/**
* see doc/zisofs_format.txt : "ZF System Use Entry Format"
*/
static
int zisofs_add_ZF(Ecma119Image *t, struct susp_info *susp, int to_ce,
int header_size_div4, int block_size_log2,
uint32_t uncompressed_size, int flag)
{
unsigned char *ZF = malloc(16);
if (ZF == NULL) {
return ISO_OUT_OF_MEM;
}
ZF[0] = 'Z';
ZF[1] = 'F';
ZF[2] = (unsigned char) 16;
ZF[3] = (unsigned char) 1;
ZF[4] = (unsigned char) 'p';
ZF[5] = (unsigned char) 'z';
ZF[6] = (unsigned char) header_size_div4;
ZF[7] = (unsigned char) block_size_log2;
iso_bb(&ZF[8], uncompressed_size, 4);
if (to_ce) {
return susp_append_ce(t, susp, ZF);
} else {
return susp_append(t, susp, ZF);
}
}
/* @param flag bit0= Do not add data but only count sua_free and ce_len
*/
static
int add_zf_field(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
size_t *sua_free, size_t *ce_len, int flag)
{
int ret, will_copy = 1, stream_type = 0, do_zf = 0;
int header_size_div4 = 0, block_size_log2 = 0;
uint32_t uncompressed_size = 0;
IsoStream *stream = NULL, *input_stream;
IsoFile *file;
/* Intimate friendship with this function in filters/zisofs.c */
int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type,
int *header_size_div4, int *block_size_log2,
uint32_t *uncompressed_size, int flag);
if (iso_node_get_type(n->node) != LIBISO_FILE)
return 2;
file = (IsoFile *) n->node;
if (t->appendable && file->from_old_session)
will_copy = 0;
stream = iso_file_get_stream(file);
while (!will_copy) { /* Obtain most original stream (image stream) */
input_stream = iso_stream_get_input_stream(stream, 0);
if (input_stream == NULL)
break;
stream = input_stream;
}
/* Determine stream type : 1=ziso , -1=osiz , 0=other */
ret = ziso_is_zisofs_stream(stream, &stream_type, &header_size_div4,
&block_size_log2, &uncompressed_size, 0);
if (ret < 0)
return ret;
if (stream_type == 1 && will_copy) {
do_zf = 1;
} else if (stream_type == -1 && !will_copy) {
do_zf = 1;
/* >>> } else if (t->zisofs_magic) { */
/* >>> open stream via temporary osiz filter and read 0 bytes.
If no error: do_zf = 1; */;
/* >>> obtain
header_size_div4, block_size_log2, uncompressed_size */;
}
if (!do_zf)
return 2;
/* Account for field size */
if (*sua_free < 16 || *ce_len > 0) {
*ce_len += 16;
} else {
*sua_free -= 16;
}
if (flag & 1)
return 1;
/* write ZF field */
ret = zisofs_add_ZF(t, info, (*ce_len > 0), header_size_div4,
block_size_log2, uncompressed_size, 0);
if (ret < 0)
return ret;
return 1;
}
int aaip_xinfo_func(void *data, int flag) int aaip_xinfo_func(void *data, int flag)
{ {
if (flag & 1) { if (flag & 1) {
@ -932,6 +1035,13 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space,
} }
/* Find out whether ZF is to be added and account for its bytes */
sua_free = space - *su_size;
add_zf_field(t, n, NULL, &sua_free, ce, 1);
*su_size = space - sua_free;
if (*ce > 0 && !(flag & 1))
goto unannounced_ca;
/* obtain num_aapt from node */ /* obtain num_aapt from node */
xipt = NULL; xipt = NULL;
num_aapt = 0; num_aapt = 0;
@ -949,6 +1059,7 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space,
if (*ce > 0 && !(flag & 1)) if (*ce > 0 && !(flag & 1))
goto unannounced_ca; goto unannounced_ca;
} }
return 1; return 1;
unannounced_ca:; unannounced_ca:;
@ -1096,6 +1207,9 @@ int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
void *xipt; void *xipt;
size_t num_aapt= 0; size_t num_aapt= 0;
if (!t->aaip)
return 1;
ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt); ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt);
if (ret == 1) { if (ret == 1) {
num_aapt = aaip_count_bytes((unsigned char *) xipt, 0); num_aapt = aaip_count_bytes((unsigned char *) xipt, 0);
@ -1483,16 +1597,18 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
} }
} }
/* Obtain AAIP field string from node /* Eventually write zisofs ZF field */
ret = add_zf_field(t, n, info, &sua_free, &ce_len, 0);
if (ret < 0)
goto add_susp_cleanup;
/* Eventually obtain AAIP field string from node
and write it to directory entry or CE area. and write it to directory entry or CE area.
*/ */
ret = ISO_SUCCESS; ret = add_aa_string(t, n, info, &sua_free, &ce_len, 0);
if (ret < 0)
goto add_susp_cleanup;
if (t->aaip) {
ret = add_aa_string(t, n, info, &sua_free, &ce_len, 0);
if (ret < 0)
goto add_susp_cleanup;
}
} else { } else {