From 20adf50275a4882ceacc0a2076b998155b28426f Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sat, 17 Jan 2009 16:06:05 +0100 Subject: [PATCH] New API function iso_node_get_acl_text Fixes for problems with CE usage and reading of multiple AA fields --- libisofs/libisofs.h | 25 ++++ libisofs/node.c | 186 +++++++++++++++++++++++++ libisofs/rockridge.c | 283 ++++++++++++++++++++++++++++++++++++++ libisofs/rockridge_read.c | 5 +- 4 files changed, 497 insertions(+), 2 deletions(-) diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index d8c5563..a3f622b 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -4126,5 +4126,30 @@ int aaip_xinfo_func(void *data, int flag); #endif /* Libisofs_with_aaiP */ +/** + * Get an eventual ACL which is associated with the node. + * The result will be in "long" text form as of man acl resp. acl_to_text(). + * + * @param node + * The node that is to be inquired. + * @param text + * Will return a pointer to the eventual ACL text or NULL if the desired + * ACL is not available. Call this funtion with flag bit15 to finally + * release the memory occupied an ACL inquiry. + * @param flag + * Bitfield for control purposes + * bit0= obtain "default" ACL rather than "access" ACL + * (Linux directories can have a "default" ACL which influences + * the permissions of newly created files.) + * bit15= free memory and return 1 + * @return + * 1 on success, + * 0 if the desire ACL type is not available + * < 0 on error + * + * @since 0.6.14 + */ +int iso_node_get_acl_text(IsoNode *node, char **text, int flag); + #endif /*LIBISO_LIBISOFS_H_*/ diff --git a/libisofs/node.c b/libisofs/node.c index 3345adf..db7f117 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -10,6 +10,11 @@ #include "node.h" #include "stream.h" +#ifdef Libisofs_with_aaiP +#include "aaip_0_2.h" +#endif + + #include #include #include @@ -1317,3 +1322,184 @@ int iso_node_new_special(char *name, mode_t mode, dev_t dev, *special = new; return ISO_SUCCESS; } + + +/* ts A90116 */ +/* >>> describe + + @param flag bit15 = free memory +*/ +int iso_node_get_attrs(IsoNode *node, size_t *num_attrs, + char ***names, size_t **value_lengths, char ***values, int flag) +{ + +#ifdef Libisofs_with_aaiP + + void *xipt; + struct aaip_state *aaip= NULL; + unsigned char *rpt, *aa_string; + size_t len, todo, consumed; + int is_done = 0, first_round= 1, ret; + + if (flag & (1 << 15)) + aaip_get_decoded_attrs(&aaip, num_attrs, names, + value_lengths, values, 1 << 15); + *num_attrs = 0; + *names = NULL; + *value_lengths = NULL; + *values = NULL; + if (flag & (1 << 15)) + return 1; + + ret = iso_node_get_xinfo(node, aaip_xinfo_func, &xipt); + if (ret != 1) + return 1; + + aa_string = rpt = (unsigned char *) xipt; + len = aaip_count_bytes(rpt, 0); + while (!is_done) { + todo = len - (rpt - aa_string); + if (todo > 2048) + todo = 2048; + if (todo == 0) { + + /* >>> Out of data while still prompted to submit */; + + /* >>> invent better error code */ + return ISO_ERROR; + } + /* Allow 1 million bytes of memory consumption, 100,000 attributes */ + ret = aaip_decode_attrs(&aaip, "AA", (size_t) 1000000, (size_t) 100000, + rpt, todo, &consumed, first_round); + rpt+= consumed; + first_round= 0; + if (ret == 1) + continue; + if (ret == 2) + break; + + /* >>> "aaip_decode_attrs() reports error */; + + /* >>> invent better error code */ + return ISO_ERROR; + } + + if(rpt - aa_string != len) { + + /* >>> "aaip_decode_attrs() returns 2 but still bytes are left" */ + + /* >>> invent better error code */ + return ISO_ERROR; + } + + ret = aaip_get_decoded_attrs(&aaip, num_attrs, names, + value_lengths, values, 0); + if(ret != 1) { + + /* >>> aaip_get_decoded_attrs() failed */; + + return ISO_OUT_OF_MEM; + } + +#else /* Libisofs_with_aaiP */ + + *num_attrs = 0; + *names = NULL; + *value_lengths = NULL; + *values = NULL; + +#endif /* ! Libisofs_with_aaiP */ + + return 1; +} + + +/* ts A90116 */ +int iso_node_get_acl_text(IsoNode *node, char **text, int flag) +{ + size_t num_attrs = 0, *value_lengths = NULL, i, consumed, text_fill = 0; + size_t v_len; + char **names = NULL, **values = NULL; + unsigned char *v_data; + int ret; + + if (flag & (1 << 15)) { + if (*text != NULL) + free(*text); + *text = NULL; + return 1; + } + +#ifdef Libisofs_with_aaiP + + *text = NULL; + + ret = iso_node_get_attrs(node, &num_attrs, &names, + &value_lengths, &values, 0); + if (ret < 0) + return ret; + + for(i = 0; i < num_attrs; i++) { + if (names[i][0]) /* searching the empty name */ + continue; + + v_data = (unsigned char *) values[i]; + v_len = value_lengths[i]; + + if (flag & 1) { + /* Skip "access" ACL and address "default" ACL instead */ + ret = aaip_decode_acl(v_data, v_len, + &consumed, NULL, (size_t) 0, &text_fill, 1); + if (ret <= 0) + goto bad_decode; + if (ret != 2) { + ret = 0; + goto ex; + } + v_data += consumed; + v_len -= consumed; + } + + ret = aaip_decode_acl(v_data, v_len, + &consumed, NULL, (size_t) 0, &text_fill, 1); + if (ret <= 0) + goto bad_decode; + if (text_fill == 0) { + ret = 0; + goto ex; + } + *text = calloc(text_fill, 1); + if (*text == NULL) { + ret = ISO_OUT_OF_MEM; + goto ex; + } + ret = aaip_decode_acl(v_data, v_len, + &consumed, *text, text_fill, &text_fill, 0); + if (ret <= 0) + goto bad_decode; + break; + } + + ret = (*text != NULL); +ex:; + iso_node_get_attrs(node, &num_attrs, &names, + &value_lengths, &values, 1 << 15); /* free memory */ + return ret; + +bad_decode:; + + /* >>> something is wrong with the attribute value */; + + /* >>> invent better error code */ + ret = ISO_ERROR; + goto ex; + +#else /* Libisofs_with_aaiP */ + + *text = NULL; + return 0; + +#endif /* ! Libisofs_with_aaiP */ + +} + diff --git a/libisofs/rockridge.c b/libisofs/rockridge.c index 4a51139..e0149b1 100644 --- a/libisofs/rockridge.c +++ b/libisofs/rockridge.c @@ -7,6 +7,8 @@ * published by the Free Software Foundation. See COPYING file for details. */ +#define Libisofs_new_nm_sl_cE yes + /* ts A90116 : libisofs.h eventually defines Libisofs_with_aaiP */ #include "libisofs.h" @@ -16,7 +18,10 @@ #include "writer.h" #include "messages.h" #include "image.h" + +#ifdef Libisofs_with_aaiP #include "aaip_0_2.h" +#endif #include @@ -700,6 +705,212 @@ int aaip_xinfo_func(void *data, int flag) #endif /* Libisofs_with_aaiP */ +/* ts A90117 */ +/** + * Compute SUA lentgth and eventual Continuation Area length of field NM and + * eventually fields SL and AA. Because CA usage makes necessary the use of + * a CE entry of 28 bytes in SUA, this computation fails if not the 28 bytes + * are taken into account at start. In this case the caller should retry with + * bit0 set. + * + * @param flag bit0= assume CA usage (else return 0 on SUA overflow) + * @return 1= ok, computation of *su_size and *ce is valid + * 0= not ok, CA usage is necessary but bit0 was not set + * (*su_size and *ce stay unaltered in this case) + * <0= error: + * -1= not enough SUA space for 28 bytes of CE entry + */ +static +int susp_calc_nm_sl_aa(Ecma119Image *t, Ecma119Node *n, size_t space, + size_t *su_size, size_t *ce, int flag) +{ + char *name; + size_t namelen, su_mem, ce_mem; + +#ifdef Libisofs_with_aaiP + /* ts A90112 */ + void *xipt; + size_t num_aapt = 0, sua_free = 0; + int ret; +#endif + + su_mem = *su_size; + ce_mem = *ce; + if (*ce > 0 && !(flag & 1)) + goto unannounced_ca; + + name = get_rr_fname(t, n->node->name); + namelen = strlen(name); + free(name); + + if (flag & 1) { + /* Account for 28 bytes of CE field */ + if (*su_size + 28 > space) + return -1; + *su_size += 28; + } + + /* NM entry */ + if (*su_size + 5 + namelen <= space) { + /* ok, it fits in System Use Area */ + *su_size += 5 + namelen; + } else { + /* the NM will be divided in a CA */ + if (!(flag & 1)) + goto unannounced_ca; + namelen = namelen - (space - *su_size - 5); + *ce = 5 + namelen; + *su_size = space; + } + if (n->type == ECMA119_SYMLINK) { + /* + * for symlinks, we also need to write the SL + */ + char *dest, *cur, *prev; + size_t sl_len = 5; + int cew = (*ce != 0); /* are we writing to CA ? */ + + dest = get_rr_fname(t, ((IsoSymlink*)n->node)->dest); + prev = dest; + cur = strchr(prev, '/'); + while (1) { + size_t clen; + if (cur) { + clen = cur - prev; + } else { + /* last component */ + clen = strlen(prev); + } + + if (clen == 1 && prev[0] == '.') { + clen = 0; + } else if (clen == 2 && prev[0] == '.' && prev[1] == '.') { + clen = 0; + } + + /* flags and len for each component record (RRIP, 4.1.3.1) */ + clen += 2; + + if (!cew) { + /* we are still writing to the SUA */ + if (*su_size + sl_len + clen > space) { + /* + * ok, we need a Continuation Area anyway + * TODO this can be handled better, but for now SL + * will be completelly moved into the CA + */ + if (!(flag & 1)) + goto unannounced_ca; + cew = 1; + } else { + sl_len += clen; + } + } + if (cew) { + if (sl_len + clen > 255) { + /* we need an additional SL entry */ + if (clen > 250) { + /* + * case 1, component too large to fit in a + * single SL entry. Thus, the component need + * to be divided anyway. + * Note than clen can be up to 255 + 2 = 257. + * + * First, we check how many bytes fit in current + * SL field + */ + int fit = 255 - sl_len - 2; + if (clen - 250 <= fit) { + /* + * the component can be divided between this + * and another SL entry + */ + *ce += 255; /* this SL, full */ + sl_len = 5 + (clen - fit); + } else { + /* + * the component will need a 2rd SL entry in + * any case, so we prefer to don't write + * anything in this SL + */ + *ce += sl_len + 255; + sl_len = 5 + (clen - 250) + 2; + } + } else { + /* case 2, create a new SL entry */ + *ce += sl_len; + sl_len = 5 + clen; + } + } else { + sl_len += clen; + } + } + + if (!cur || cur[1] == '\0') { + /* cur[1] can be \0 if dest ends with '/' */ + break; + } + prev = cur + 1; + cur = strchr(prev, '/'); + } + + free(dest); + + /* and finally write the pending SL field */ + if (!cew) { + /* the whole SL fits into the SUA */ + *su_size += sl_len; + } else { + *ce += sl_len; + } + + } + +#ifdef Libisofs_with_aaiP + /* ts A90112 */ + xipt = NULL; + +#ifdef Libisofs_with_aaip_dummY + + num_aapt = 28; + aaip_xinfo_func(NULL, 0); /* to avoid compiler warning */ + +#else /* Libisofs_with_aaip_dummY */ + + /* obtain num_aapt from node */ + num_aapt = 0; + + /* >>> if AAIP is enabled */ + if (1) { + + ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt); + if (ret == 1) { + num_aapt = aaip_count_bytes((unsigned char *) xipt, 0); + } + } + +#endif /* ! Libisofs_with_aaip_dummY */ + + /* let the expert decide where to add num_aapt */ + if (num_aapt > 0) { + sua_free = space - *su_size; + aaip_add_AA(NULL, NULL, NULL, num_aapt, &sua_free, ce, 1); + *su_size = space - sua_free; + if (*ce > 0 && !(flag & 1)) + goto unannounced_ca; + } + +#endif /* Libisofs_with_aaiP */ + + return 1; + +unannounced_ca:; + *su_size = su_mem; + *ce = ce_mem; + return 0; +} + + /** * Compute the length needed for write all RR and SUSP entries for a given * node. @@ -721,10 +932,16 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t space, #ifdef Libisofs_with_aaiP /* ts A90112 */ +#ifndef Libisofs_new_nm_sl_cE void *xipt; size_t num_aapt = 0, sua_free = 0; +#endif /* Libisofs_new_nm_sl_cE */ + int ret; +#else /* Libisofs_with_aaiP */ +#ifdef Libisofs_new_nm_sl_cE int ret; #endif +#endif /* ! Libisofs_with_aaiP */ /* space min is 255 - 33 - 37 = 185 * At the same time, it is always an odd number, but we need to pad it @@ -763,6 +980,16 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t space, } if (type == 0) { + +#ifdef Libisofs_new_nm_sl_cE + + /* Try without CE */ + ret = susp_calc_nm_sl_aa(t, n, space, &su_size, ce, 0); + if (ret == 0) /* Retry with CE */ + susp_calc_nm_sl_aa(t, n, space, &su_size, ce, 1); + +#else /* Libisofs_new_nm_sl_cE */ + char *name = get_rr_fname(t, n->node->name); size_t namelen = strlen(name); free(name); @@ -921,6 +1148,8 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t space, #endif /* Libisofs_with_aaiP */ +#endif /* ! Libisofs_new_nm_sl_cE */ + } else { /* "." or ".." entry */ @@ -1017,6 +1246,11 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, #endif size_t aaip_er_len= 0; +#ifdef Libisofs_new_nm_sl_cE + size_t su_size_pd, ce_len_pd; /* predicted sizes of SUA and CA */ + int ce_is_predicted = 0; +#endif + if (t == NULL || n == NULL || info == NULL) { return ISO_NULL_POINTER; } @@ -1110,6 +1344,20 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, sua_free = space - info->suf_len; +#ifdef Libisofs_new_nm_sl_cE + /* ts A90117 */ + /* Try whether NM, SL, AA will fit into SUA */ + su_size_pd = info->suf_len; + ce_len_pd = ce_len; + ret = susp_calc_nm_sl_aa(t, n, space, &su_size_pd, &ce_len_pd, 0); + if (ret == 0) { /* Have to use CA. 28 bytes of CE are necessary */ + susp_calc_nm_sl_aa(t, n, space, &su_size_pd, &ce_len_pd, 1); + sua_free -= 28; + ce_is_predicted = 1; + } + +#endif /* ! Libisofs_new_nm_sl_cE */ + /* NM entry */ if (5 + namelen <= sua_free) { /* ok, it fits in System Use Area */ @@ -1118,7 +1366,13 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, } else { /* the NM will be divided in a CE */ nm_type = 1; + +#ifdef Libisofs_new_nm_sl_cE + namelen = namelen - (sua_free - 5); +#else namelen = namelen - (sua_free - 5 - 28); +#endif + ce_len = 5 + namelen; sua_free = 0; } @@ -1166,6 +1420,15 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, * TODO this can be handled better, but for now SL * will be completelly moved into the CA */ + +#ifdef Libisofs_new_nm_sl_cE + + /* ts A90117 */ + /* sua_free, ce_len, nm_type already account for CE */ + cew = 1; + +#else /* Libisofs_new_nm_sl_cE */ + if (28 <= sua_free) { /* the CE entry fills without reducing NM */ sua_free -= 28; @@ -1177,6 +1440,9 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, sua_free = 0; cew = 1; } + +#endif /* ! Libisofs_new_nm_sl_cE */ + } else { /* add the component */ ret = rrip_SL_append_comp(&n_comp, &comps, prev, @@ -1293,16 +1559,33 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, * Write the NM part that fits in SUA... Note that CE * entry and NM in the continuation area is added below */ + +#ifdef Libisofs_new_nm_sl_cE + namelen = space - info->suf_len - 28 * (!!ce_is_predicted) - 5; +#else namelen = space - info->suf_len - 28 - 5; +#endif + ret = rrip_add_NM(t, info, name, namelen, 1, 0); if (ret < 0) { goto add_susp_cleanup; } } +#ifdef Libisofs_new_nm_sl_cE + + if (ce_is_predicted) { + /* Add the CE entry */ + ret = susp_add_CE(t, ce_len_pd, info); + +#else /* Libisofs_new_nm_sl_cE */ + if (ce_len > 0) { /* Add the CE entry */ ret = susp_add_CE(t, ce_len, info); + +#endif /* ! Libisofs_new_nm_sl_cE */ + if (ret < 0) { goto add_susp_cleanup; } diff --git a/libisofs/rockridge_read.c b/libisofs/rockridge_read.c index a87ba49..456f99b 100644 --- a/libisofs/rockridge_read.c +++ b/libisofs/rockridge_read.c @@ -433,7 +433,7 @@ int read_aaip_AA(struct susp_sys_user_entry *sue, char aa[2], } /* Eventually create or grow storage */ - if (*aa_size == 0 || *aa_string == 0) { + if (*aa_size == 0 || *aa_string == NULL) { *aa_size = *aa_len + sue->len_sue[0]; *aa_string = calloc(*aa_size, 1); *aa_len = 0; @@ -461,7 +461,8 @@ int read_aaip_AA(struct susp_sys_user_entry *sue, char aa[2], /* Append sue payload */ memcpy(aapt + 5, sue->data.AA.comps, sue->len_sue[0]); - *is_done = sue->data.AA.flags[0] & 1; + *aa_len += sue->len_sue[0]; + *is_done = !(sue->data.AA.flags[0] & 1); return ISO_SUCCESS; }