Introduced system adapters for getting and setting EA and ACL
This commit is contained in:
parent
6caddd2808
commit
aac9c23152
328
doc/susp_aaip_0_2.txt
Normal file
328
doc/susp_aaip_0_2.txt
Normal file
@ -0,0 +1,328 @@
|
||||
|
||||
|
||||
Arbitrary Attribute Interchange Protocol
|
||||
|
||||
Draft version 0.2
|
||||
Dec 19 2008
|
||||
|
||||
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 field with adjustable name (Signature Word).
|
||||
The name is defined in an ER field of which the content form is described here.
|
||||
Recommended is to use the name "AA" which collides neither with SUSP 1.12 nor
|
||||
with RRIP 1.12.
|
||||
The field has been designed to be as similar to the RRIP field SL as possible.
|
||||
|
||||
Since the size of a SUSP field is limited to 255, multiple fields may be
|
||||
needed to describe one component. The CE mechanism of SUSP shall be used to
|
||||
address enough storage if needed.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
System Entries Provided by this Specification
|
||||
|
||||
* AA (or another name which does not disturb other co-existing SUSP protocols)
|
||||
|
||||
Description of the "AA" System Use Entry
|
||||
|
||||
The field has exactly the same layout as RRIP field 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 AA fields form the Attribute List of a file object with
|
||||
a pare number of components. Each two consequtive components form a pair of
|
||||
Name and Value. The empty name is reserved for a compact representation of
|
||||
ALCs. The meaning of any other name is not specified by this document.
|
||||
|
||||
All AA fields except the last one shall have the CONTINUE flag set. An AA
|
||||
field with CONTINUE set to 0 indicates the end of the Attribute List.
|
||||
|
||||
The format of the "AA" System Use Field is as follows:
|
||||
|
||||
[1] "BP 1 to BP 2 - Signature Word" shall be (41)(41) ("AA") resp. the word
|
||||
that is defined in the ER field. See below.
|
||||
|
||||
[2] "BP 3 - Length" shall specify as an 8-bit number the length in bytes of
|
||||
the "AA" 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 AA field continues in the next AA field.
|
||||
All other bits shall be set to 0.
|
||||
|
||||
[5] "BP 6 to Length - Component Area" shall contain Component Records
|
||||
as described below.
|
||||
|
||||
| 'A' | 'A' | LENGTH | 1 | FLAGS | COMPONENT AREA |
|
||||
|
||||
|
||||
Within "AA" fields 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 AA field then it shall be continued in following AA fields.
|
||||
|
||||
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 field.
|
||||
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.
|
||||
|
||||
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 "AA" System Use Entry may be continued in the
|
||||
Component Area of the next recorded "AA" 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
|
||||
AA Component Record.
|
||||
The following bits are defined but may not be set if the Component
|
||||
Record shall carry payload. (Their use case is unclear yet.)
|
||||
1 CURRENT This Component Record refers to the current
|
||||
directory.
|
||||
2 PARENT This Component Record refers to the parent of
|
||||
the current directory.
|
||||
3 ROOT This Component Record refers to root directory.
|
||||
|
||||
all others are RESERVED and shall be 0.
|
||||
|
||||
No more than one of "AA" Component Flag Bits 0-3 shall be set to ONE.
|
||||
|
||||
[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 AA fields
|
||||
|
||||
Field 1 contains the Component Record of Name and one Component Record of
|
||||
Value :
|
||||
{ 'A', 'A', 255, 1, 1,
|
||||
0, 4, 'n', 'a', 'm', 'e',
|
||||
1, 255, 'l', 'o', 'n', 'g', ... 238 more bytes, 13 go to next AA ... }
|
||||
Field 2 contains the rest of "long...content" and the complete second pair.
|
||||
It marks the end of the Attribute List :
|
||||
{ 'A', 'A', 38, 1, 0,
|
||||
... 13 remaining bytes of the Component Record in first field ...
|
||||
0, 7, 'c', 'o', 'n', 't', 'e', 'n', 't',
|
||||
0, 3, 'o', 'n', 'e',
|
||||
0, 4, 'm', 'o', 'r', 'e' }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
1 ACL_USER_OBJ permissions of owning user (as of PX field)
|
||||
2 ACL_USER of arbitrary user, with name as qualifier
|
||||
3 ACL_GROUP_OBJ permissions of owning group (as of PX field)
|
||||
4 ACL_GROUP of arbitrary group, with name as qualifier
|
||||
5 ACL_MASK restricts 2, 3, and 4 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 like 2, with numeric user id as qualifier
|
||||
12 ACL_GROUP_N like 4, with numeric group id as qualifier
|
||||
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.
|
||||
|
||||
If any of ACL_USER_OBJ, ACL_GROUP_OBJ, ACL_OTHER are missing then the settings
|
||||
from the PX field shall get into effect. If they exist then they shall override
|
||||
the PX field.
|
||||
|
||||
A numeric qualifier is a binary number of variable length. 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 fields. The ids of owning user
|
||||
and owning group shall be taken from the PX field 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 switching is controlled by the EXEC bit.
|
||||
0 "access" ACL
|
||||
1 "default" ACL
|
||||
The bits for WRITE, READ, QUALIFIER shall be 0 with SWITCH_MARK.
|
||||
|
||||
The 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--
|
||||
{ 'A', 'A', 28, 1, 0,
|
||||
0, 0,
|
||||
0, 19, 0x16,
|
||||
0x2E, 4, 'l', 'i', 's', 'a',
|
||||
0x34,
|
||||
0x4E, 7, 't', 'o', 'o', 'l', 'i', 'e', 's',
|
||||
0x54,
|
||||
0x64 }
|
||||
|
||||
Example: An entry with very long qualifier u:His_Excellency_..._the_Boss:r--
|
||||
0x2C, 255, 'H', 'i', 's', '_', 'E', 'x', 'c', 'e', 'l', 'e',
|
||||
... 117 more bytes ...,
|
||||
8, 't', 'h', 'e', '_', 'B', 'o', 's', 's',
|
||||
|
||||
Example: User number 71 in numerical form gets rwx
|
||||
0xAF, 1, 71,
|
||||
Group number 65534 gets r-x
|
||||
0xCD, 2, 255, 254,
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
About Names and Numeric Identifiers
|
||||
|
||||
It makes an important difference whether qualifiers are represented as names
|
||||
or as id numbers. By storing names (and usually wasting space) it is possible
|
||||
to control permissions in a way that is portable between uncoordinated
|
||||
computers as long as the human readable user/group names are present on both
|
||||
sides. POSIX File ID numbers make most sense in backups which shall be read
|
||||
by the same system which wrote it.
|
||||
Rock Ridge can only record POSIX File Ids but not user or group names.
|
||||
|
||||
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
|
||||
field 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 AA 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 1001 gets associated with user name "lisa"
|
||||
|
||||
0x08, 13, 0, 233,3,0,0, 0,0,3,233, 'l', 'i', 's', 'a',
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Specification of the ER System Use Entry Values for AAIP:
|
||||
|
||||
The Extension Version number for this version of AAIP shall be 1.
|
||||
|
||||
The Extension Identifier field shall be "AAIP_0002" with Identifier Length 9.
|
||||
|
||||
The mandatory content form of the Extension Descriptor is
|
||||
"AA PROVIDES VIA AAIP 0.2 SUPPORT FOR ARBITRARY FILE ATTRIBUTES IN ISO 9660 IMAGES"
|
||||
with possibly two letters other than "AA" at the start of the string.
|
||||
The Description Length is 81.
|
||||
|
||||
The reader of AAIP shall take the actual name of the AA field from BP 19 and
|
||||
BP 20 of the ER field.
|
||||
|
||||
The recommended content of the Extension Source is
|
||||
"PLEASE CONTACT THE LIBBURNIA PROJECT VIA LIBBURNIA-PROJECT.ORG".
|
||||
The corresponding Source Length is 62.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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] AA Field ) Qualifier
|
||||
[1:1..n] << one of >>
|
||||
Component Record / \ \
|
||||
[1..m:1..n] Translation Entry , Name , Numeric Id
|
||||
AA Field | | |
|
||||
[1:1..n] [1:1..n] [1:1]
|
||||
\ | /
|
||||
Qualifier Record
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Revoked drafts:
|
||||
|
||||
There was a draft AAIP 0.0 with ER signature "AAIP_2008A". It did not resemble
|
||||
the existing field SL and therefore shall not be used by writers of ISO images.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
References:
|
||||
|
||||
ECMA-119 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
|
||||
(especially field SL)
|
||||
|
||||
|
283
test/aaip-os-freebsd.c
Normal file
283
test/aaip-os-freebsd.c
Normal file
@ -0,0 +1,283 @@
|
||||
|
||||
/*
|
||||
|
||||
aaip-os-freebsd.c
|
||||
Arbitrary Attribute Interchange Protocol , system adapter for getting and
|
||||
setting of ACLs and XFS-style Extended Attributes.
|
||||
|
||||
To be included by aaip_0_2.c
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/acl.h>
|
||||
|
||||
|
||||
/* ------------------------------ 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
|
||||
bit15= free text and return 1
|
||||
@return > 0 ok
|
||||
-1 failure of system ACL service (see errno)
|
||||
*/
|
||||
int aaip_get_acl_text(char *path, char **text, int flag)
|
||||
{
|
||||
acl_t acl= NULL;
|
||||
|
||||
if(flag & (1 << 15)) {
|
||||
if(*text != NULL)
|
||||
acl_free(text);
|
||||
*text= NULL;
|
||||
return(1);
|
||||
}
|
||||
*text= NULL;
|
||||
|
||||
/* Note: no ACL_TYPE_DEFAULT in FreeBSD */
|
||||
if(flag & 1)
|
||||
return(0);
|
||||
|
||||
acl= acl_get_file(path, ACL_TYPE_ACCESS);
|
||||
|
||||
if(acl == NULL)
|
||||
return(-1);
|
||||
*text= acl_to_text(acl, NULL);
|
||||
acl_free(acl);
|
||||
if(*text == NULL)
|
||||
return(-1);
|
||||
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
|
||||
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, value_ret;
|
||||
size_t a_acl_len= 0, d_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 */
|
||||
if(*names != NULL)
|
||||
list= (*names)[0];
|
||||
{ret= 1; goto ex;}
|
||||
}
|
||||
|
||||
*num_attrs= 0;
|
||||
*names= NULL;
|
||||
*value_lengths= NULL;
|
||||
*values= NULL;
|
||||
|
||||
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= *num_attrs; i < num_names; i++)
|
||||
(*names)[i]= NULL;
|
||||
for(i= 0; i < num_names; i++) {
|
||||
(*values)[i]= NULL;
|
||||
(*value_lengths)[i]= 0;
|
||||
}
|
||||
|
||||
if(flag & 1) { /* Obtain ACL */
|
||||
/* access-ACL */
|
||||
ret= aaip_get_acl_text(path, &acl_text, 0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
ret= aaip_encode_acl(acl_text, &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)++;
|
||||
}
|
||||
|
||||
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(list != NULL)
|
||||
free(list);
|
||||
if(*names != NULL)
|
||||
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)
|
||||
*/
|
||||
int aaip_set_acl_text(char *path, char *text, int flag)
|
||||
{
|
||||
int ret;
|
||||
acl_t acl= NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* 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 )
|
||||
|
||||
*/
|
||||
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;
|
||||
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);
|
||||
ret= aaip_set_acl_text(path, acl_text, 0);
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
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);
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret= 1;
|
||||
ex:;
|
||||
if(acl_text != NULL)
|
||||
free(acl_text);
|
||||
if(list != NULL)
|
||||
free(list);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
371
test/aaip-os-linux.c
Normal file
371
test/aaip-os-linux.c
Normal file
@ -0,0 +1,371 @@
|
||||
|
||||
/*
|
||||
|
||||
aaip-os-linux.c
|
||||
Arbitrary Attribute Interchange Protocol , system adapter for getting and
|
||||
setting of ACLs and XFS-style Extended Attributes.
|
||||
|
||||
To be included by aaip_0_2.c
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/acl.h>
|
||||
#include <attr/xattr.h>
|
||||
|
||||
#define Aaip_acl_attrnamE "system.posix_acl_access"
|
||||
|
||||
|
||||
/* ------------------------------ 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
|
||||
bit15= free text and return 1
|
||||
@return > 0 ok
|
||||
-1 failure of system ACL service (see errno)
|
||||
*/
|
||||
int aaip_get_acl_text(char *path, char **text, int flag)
|
||||
{
|
||||
acl_t acl= NULL;
|
||||
|
||||
if(flag & (1 << 15)) {
|
||||
if(*text != NULL)
|
||||
acl_free(text);
|
||||
*text= NULL;
|
||||
return(1);
|
||||
}
|
||||
*text= NULL;
|
||||
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);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* 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 local ACL attribute
|
||||
(e.g. system.posix_acl_access)
|
||||
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 a_acl_len= 0, d_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 */
|
||||
if(*names != NULL)
|
||||
list= (*names)[0];
|
||||
{ret= 1; goto ex;}
|
||||
}
|
||||
|
||||
*num_attrs= 0;
|
||||
*names= NULL;
|
||||
*value_lengths= NULL;
|
||||
*values= NULL;
|
||||
|
||||
/* Set up arrays */
|
||||
if(!(flag & 4)) { /* Get xattr names */
|
||||
list_size= listxattr(path, list, 0);
|
||||
if(list_size == -1)
|
||||
{ret= -1; goto ex;}
|
||||
list= calloc(list_size, 1);
|
||||
if(list == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
list_size= listxattr(path, list, list_size);
|
||||
if(list_size == -1)
|
||||
{ret= -1; goto ex;}
|
||||
for(i= 0; i < list_size; i+= strlen(list + i) + 1)
|
||||
num_names++;
|
||||
}
|
||||
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;}
|
||||
|
||||
if(!(flag & 4))
|
||||
for(i= 0; i < list_size && num_names > *num_attrs;
|
||||
i+= strlen(list + i) + 1) {
|
||||
if(!(flag & 8))
|
||||
if(strcmp(list + i, Aaip_acl_attrnamE) == 0)
|
||||
continue;
|
||||
(*names)[(*num_attrs)++]= list + i;
|
||||
}
|
||||
for(i= *num_attrs; i < num_names; i++)
|
||||
(*names)[i]= NULL;
|
||||
for(i= 0; i < num_names; i++) {
|
||||
(*values)[i]= NULL;
|
||||
(*value_lengths)[i]= 0;
|
||||
}
|
||||
|
||||
if(!(flag & 4)) { /* Get xattr values */
|
||||
for(i= 0; i < *num_attrs; i++) {
|
||||
if(!(flag & 8))
|
||||
if(strcmp((*names)[i], Aaip_acl_attrnamE) == 0)
|
||||
continue;
|
||||
value_ret= getxattr(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;}
|
||||
(*value_lengths)[i]= getxattr(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;
|
||||
}
|
||||
}
|
||||
|
||||
if(flag & 1) { /* Obtain ACL */
|
||||
/* access-ACL */
|
||||
ret= aaip_get_acl_text(path, &acl_text, 0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
ret= aaip_encode_acl(acl_text, &a_acl_len, &a_acl, flag & 2);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
aaip_get_acl_text("", &acl_text, 1 << 15); /* free */
|
||||
|
||||
/* eventually default-ACL */
|
||||
ret= aaip_get_acl_text(path, &acl_text, 1);
|
||||
if(ret > 0) {
|
||||
/* encode and append to a_acl */;
|
||||
ret= aaip_encode_acl(acl_text, &d_acl_len, &d_acl, (flag & 2) | 4);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
acl= calloc(a_acl_len + d_acl_len + 1, 1);
|
||||
if(acl == NULL)
|
||||
{ret= -1; goto ex;}
|
||||
if(a_acl_len)
|
||||
memcpy(acl, a_acl, a_acl_len);
|
||||
if(d_acl_len)
|
||||
memcpy(acl + a_acl_len, d_acl, d_acl_len);
|
||||
acl_len= a_acl_len + d_acl_len;
|
||||
} else {
|
||||
acl= a_acl;
|
||||
a_acl= NULL;
|
||||
acl_len= a_acl_len;
|
||||
}
|
||||
|
||||
/* 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)++;
|
||||
}
|
||||
|
||||
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(list != NULL)
|
||||
free(list);
|
||||
if(*names != NULL)
|
||||
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)
|
||||
*/
|
||||
int aaip_set_acl_text(char *path, char *text, int flag)
|
||||
{
|
||||
int ret;
|
||||
acl_t acl= NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* 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 ACL attribute
|
||||
(e.g. system.posix_acl_access)
|
||||
@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
|
||||
|
||||
*/
|
||||
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;
|
||||
char *acl_text= NULL, *list= NULL;
|
||||
|
||||
if(flag & 2) /* Delete all file attributes */
|
||||
list_size= listxattr(path, list, 0);
|
||||
if(list_size > 0) { /* Delete all file attributes */
|
||||
list= calloc(list_size, 1);
|
||||
if(list == NULL)
|
||||
{ret= -5; goto ex;}
|
||||
list_size= listxattr(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(strcmp(list + i, Aaip_acl_attrnamE) == 0)
|
||||
continue;
|
||||
ret= removexattr(path, list + i);
|
||||
if(ret == -1)
|
||||
{ret= -5; goto ex;}
|
||||
}
|
||||
free(list); list= NULL;
|
||||
}
|
||||
|
||||
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(strcmp(names[i], Aaip_acl_attrnamE) == 0)
|
||||
continue;
|
||||
ret= setxattr(path, names[i], values[i], value_lengths[i], 0);
|
||||
if(ret == -1)
|
||||
{ret= -4; goto ex;}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
ret= aaip_set_acl_text(path, acl_text, 0);
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
/* "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);
|
||||
if(ret <= 0)
|
||||
{ret= -3; goto ex;}
|
||||
}
|
||||
ret= 1;
|
||||
ex:;
|
||||
if(acl_text != NULL)
|
||||
free(acl_text);
|
||||
if(list != NULL)
|
||||
free(list);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
364
test/aaip_0_2.c
364
test/aaip_0_2.c
@ -7,8 +7,6 @@
|
||||
See test/aaip_0_2.h
|
||||
http://libburnia-project.org/wiki/AAIP
|
||||
|
||||
>>> ACLs
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@ -54,8 +52,8 @@ static int aaip_encode_pair(char *name, size_t attr_length, char *attr,
|
||||
@param aa_name The 2 byte SUSP Signature Word of the fields
|
||||
@param num_attrs Number of attributes
|
||||
@param names Array of pointers to 0 terminated name strings
|
||||
@param attr_lengths Array of byte lengths for each attribute payload
|
||||
@param attrs Array of pointers to the attribute payload bytes
|
||||
@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
|
||||
@ -67,7 +65,7 @@ static int aaip_encode_pair(char *name, size_t attr_length, char *attr,
|
||||
*/
|
||||
unsigned int aaip_encode(char aa_name[2],
|
||||
unsigned int num_attrs, char **names,
|
||||
size_t *attr_lengths, char **attrs,
|
||||
size_t *value_lengths, char **values,
|
||||
size_t *result_len, unsigned char **result, int flag)
|
||||
{
|
||||
size_t mem_size= 0, comp_size;
|
||||
@ -76,7 +74,7 @@ unsigned int aaip_encode(char aa_name[2],
|
||||
/* Predict memory needs, number of SUSP fields and component records */
|
||||
*result_len= 0;
|
||||
for(i= 0; i < num_attrs; i++) {
|
||||
ret= aaip_encode_pair(names[i], attr_lengths[i], attrs[i],
|
||||
ret= aaip_encode_pair(names[i], value_lengths[i], values[i],
|
||||
&num_recs, &comp_size, NULL, (size_t) 0, 1);
|
||||
if(ret <= 0)
|
||||
return(ret);
|
||||
@ -96,7 +94,7 @@ unsigned int aaip_encode(char aa_name[2],
|
||||
|
||||
/* Encode pairs into result */
|
||||
for(i= 0; i < num_attrs; i++) {
|
||||
ret= aaip_encode_pair(names[i], attr_lengths[i], attrs[i],
|
||||
ret= aaip_encode_pair(names[i], value_lengths[i], values[i],
|
||||
&num_recs, &comp_size, *result, *result_len, 0);
|
||||
if(ret <= 0)
|
||||
return(ret);
|
||||
@ -460,6 +458,20 @@ struct aaip_state {
|
||||
int pair_status;
|
||||
unsigned int pairs_skipped;
|
||||
|
||||
/* status of aaip_decode_attrs() */
|
||||
size_t list_mem_used;
|
||||
size_t list_size;
|
||||
size_t list_num_attrs;
|
||||
char **list_names;
|
||||
size_t *list_value_lengths;
|
||||
char **list_values;
|
||||
char *name_buf;
|
||||
size_t name_buf_size;
|
||||
size_t name_buf_fill;
|
||||
char *value_buf;
|
||||
size_t value_buf_size;
|
||||
size_t value_buf_fill;
|
||||
int list_pending_pair;
|
||||
};
|
||||
|
||||
|
||||
@ -472,7 +484,7 @@ size_t aaip_sizeof_aaip_state(void)
|
||||
}
|
||||
|
||||
|
||||
int aaip_init(struct aaip_state *aaip, char aa_name[2], int flag)
|
||||
int aaip_init_aaip_state(struct aaip_state *aaip, char aa_name[2], int flag)
|
||||
{
|
||||
aaip->aa_name[0]= aa_name[0];
|
||||
aaip->aa_name[1]= aa_name[1];
|
||||
@ -497,6 +509,19 @@ int aaip_init(struct aaip_state *aaip, char aa_name[2], int flag)
|
||||
aaip->pair_status= 2;
|
||||
aaip->pairs_skipped= 0;
|
||||
|
||||
aaip->list_mem_used= 0;
|
||||
aaip->list_size= 0;
|
||||
aaip->list_num_attrs= 0;
|
||||
aaip->list_names= NULL;
|
||||
aaip->list_value_lengths= NULL;
|
||||
aaip->list_values= NULL;
|
||||
aaip->name_buf= NULL;
|
||||
aaip->name_buf_size= 0;
|
||||
aaip->name_buf_fill= 0;
|
||||
aaip->value_buf= NULL;
|
||||
aaip->value_buf_size= 0;
|
||||
aaip->value_buf_fill= 0;
|
||||
aaip->list_pending_pair= 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
@ -998,7 +1023,11 @@ int aaip_skip_component(struct aaip_state *aaip, int flag)
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- Pair Level Interface ------------------------ */
|
||||
|
||||
/*
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= do not skip oversized component but return -2
|
||||
@return see aaip_decode_pair
|
||||
*/
|
||||
static int aaip_advance_pair(struct aaip_state *aaip,
|
||||
@ -1020,6 +1049,8 @@ retry:;
|
||||
}
|
||||
ret= aaip_fetch_data(aaip, wpt, size, &num, 0);
|
||||
if(ret == -2) { /* insufficient result size */
|
||||
if(flag & 1)
|
||||
return(-2);
|
||||
ret= aaip_skip_component(aaip, 0);
|
||||
*name_fill= *value_fill= 0;
|
||||
aaip->pairs_skipped++;
|
||||
@ -1074,8 +1105,12 @@ retry:;
|
||||
@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
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= do not skip oversized pair but return -2
|
||||
@return <0 error
|
||||
-3 buffer full (program error)
|
||||
-2 insufficient result_size (only with flag bit0)
|
||||
-1 non-AA field detected
|
||||
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
|
||||
@ -1120,7 +1155,7 @@ int aaip_decode_pair(struct aaip_state *aaip,
|
||||
{ret= -1; goto ex;}
|
||||
} else if(ret == 0) { /* buffer overflow */;
|
||||
/* should not happen with correct usage */
|
||||
{ret= -2; goto ex;}
|
||||
{ret= -3; goto ex;}
|
||||
} else if(ret == 1) { /* no component record complete */
|
||||
goto ex;
|
||||
} else if(ret == 2) { /* component record complete, may be delivered */
|
||||
@ -1134,7 +1169,7 @@ int aaip_decode_pair(struct aaip_state *aaip,
|
||||
|
||||
*consumed= num_data;
|
||||
ret= aaip_advance_pair(aaip, name, name_size, name_fill,
|
||||
value, value_size, value_fill, 0);
|
||||
value, value_size, value_fill, flag & 1);
|
||||
if(aaip->aa_ends == 3) {
|
||||
if(ret >= 2 && ret <= 4)
|
||||
ret= 4;
|
||||
@ -1153,6 +1188,299 @@ unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag)
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- List Level Interface ------------------------ */
|
||||
|
||||
|
||||
#define Aaip_initial_name_leN 256
|
||||
#define Aaip_initial_value_leN 256
|
||||
#define Aaip_initial_list_sizE 2
|
||||
#define Aaip_list_enlargeR 1.5
|
||||
|
||||
|
||||
/*
|
||||
@param flag Bitfield for control purposes
|
||||
bit0= do not update *buf_size
|
||||
*/
|
||||
static int aaip_enlarge_buf(struct aaip_state *aaip, size_t memory_limit,
|
||||
size_t item_size, char **buf, size_t *buf_size, int flag)
|
||||
{
|
||||
size_t new_size;
|
||||
char *new_buf;
|
||||
|
||||
new_size= *buf_size * Aaip_list_enlargeR;
|
||||
if(aaip->list_mem_used + (new_size - *buf_size) * item_size >= memory_limit)
|
||||
return(3);
|
||||
aaip->list_mem_used+= (new_size - *buf_size) * item_size;
|
||||
new_buf= realloc(*buf, new_size * item_size);
|
||||
if(new_buf == NULL)
|
||||
return(-1);
|
||||
*buf= new_buf;
|
||||
if(!(flag & 1))
|
||||
*buf_size= new_size;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* 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 aa_name The Signature Word (advised is "AA")
|
||||
@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 with the given handle
|
||||
(also in effect if *handle is NULL)
|
||||
bit15= end decoding :
|
||||
Free handle and its intermediate list memory.
|
||||
@return <=0 error
|
||||
-3 program error, unexpected reply from lower layers
|
||||
-2 non-AA-field detected, arrays are complete,
|
||||
call aaip_get_decoded_attrs()
|
||||
-1 out of memory
|
||||
1 not complete yet, submit more data
|
||||
2 arrays are complete, call aaip_get_decoded_attrs()
|
||||
3 limit exceeded, not complete yet,
|
||||
enlarge memory_limit or 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, char aa_name[2],
|
||||
size_t memory_limit, size_t num_attr_limit,
|
||||
unsigned char *data, size_t num_data, size_t *consumed,
|
||||
int flag)
|
||||
{
|
||||
int ret, was_non_aa= 0;
|
||||
struct aaip_state *aaip;
|
||||
size_t h_num, *h_lengths, i, new_mem;
|
||||
char **h_names, **h_values;
|
||||
|
||||
if(flag & (1 << 15)) {
|
||||
if(*handle == NULL)
|
||||
return(0);
|
||||
ret= aaip_get_decoded_attrs(handle, &h_num, &h_names, &h_lengths, &h_values,
|
||||
0);
|
||||
if(ret > 0)
|
||||
aaip_get_decoded_attrs(handle, &h_num, &h_names, &h_lengths, &h_values,
|
||||
1 << 15);
|
||||
if((*handle)->name_buf != NULL)
|
||||
free((*handle)->name_buf);
|
||||
if((*handle)->value_buf != NULL)
|
||||
free((*handle)->value_buf);
|
||||
free((char *) *handle);
|
||||
*handle= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
aaip= *handle;
|
||||
if(aaip == NULL || (flag & 1)) {
|
||||
aaip= *handle= calloc(1, sizeof(struct aaip_state));
|
||||
if(*handle == NULL)
|
||||
return(-1);
|
||||
aaip_init_aaip_state(*handle, aa_name, 0);
|
||||
}
|
||||
if(aaip->list_names == NULL || aaip->list_values == NULL ||
|
||||
aaip->list_value_lengths == NULL) {
|
||||
/* Initialize arrays */
|
||||
aaip->list_size= Aaip_initial_list_sizE;
|
||||
if(num_attr_limit > 0 && num_attr_limit < aaip->list_size)
|
||||
aaip->list_size= num_attr_limit;
|
||||
new_mem= aaip->list_size * (2*sizeof(char *) + sizeof(size_t)) +
|
||||
Aaip_initial_name_leN + Aaip_initial_value_leN;
|
||||
if(aaip->list_mem_used + new_mem >= memory_limit)
|
||||
return(3);
|
||||
aaip->list_mem_used+= new_mem;
|
||||
aaip->list_names= calloc(sizeof(char *), aaip->list_size);
|
||||
aaip->list_value_lengths= calloc(sizeof(size_t), aaip->list_size);
|
||||
aaip->list_values= calloc(sizeof(char *), aaip->list_size);
|
||||
if(aaip->list_names == NULL || aaip->list_value_lengths == NULL ||
|
||||
aaip->list_values == NULL)
|
||||
return(-1);
|
||||
for(i= 0; i < aaip->list_size; i++) {
|
||||
aaip->list_names[i]= NULL;
|
||||
aaip->list_value_lengths[i]= 0;
|
||||
aaip->list_values[i]= NULL;
|
||||
}
|
||||
}
|
||||
if(aaip->name_buf == NULL || aaip->value_buf == NULL) {
|
||||
new_mem= Aaip_initial_name_leN + Aaip_initial_value_leN;
|
||||
if(aaip->list_mem_used >= memory_limit)
|
||||
return(3);
|
||||
aaip->list_mem_used+= new_mem;
|
||||
aaip->name_buf= calloc(sizeof(char *), Aaip_initial_name_leN);
|
||||
aaip->value_buf= calloc(sizeof(char *), Aaip_initial_value_leN);
|
||||
if(aaip->name_buf == NULL || aaip->value_buf == NULL)
|
||||
return(-1);
|
||||
aaip->name_buf_size= Aaip_initial_name_leN;
|
||||
aaip->value_buf_size= Aaip_initial_name_leN;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
if(aaip->list_pending_pair > 0) {
|
||||
/* the buffer holds a complete pair from a previous memory limit refusal */
|
||||
ret= aaip->list_pending_pair;
|
||||
aaip->list_pending_pair= 0;
|
||||
} else {
|
||||
ret= aaip_decode_pair(aaip, data, num_data, consumed,
|
||||
aaip->name_buf, aaip->name_buf_size, &aaip->name_buf_fill,
|
||||
aaip->value_buf, aaip->value_buf_size, &aaip->value_buf_fill,
|
||||
1);
|
||||
}
|
||||
if(ret == -2) { /* insufficient result_size */
|
||||
if(aaip->first_is_name)
|
||||
ret= aaip_enlarge_buf(aaip, memory_limit, (size_t) 1, &(aaip->name_buf),
|
||||
&(aaip->name_buf_size), 0);
|
||||
else
|
||||
ret= aaip_enlarge_buf(aaip, memory_limit, (size_t) 1,
|
||||
&(aaip->value_buf), &(aaip->value_buf_size), 0);
|
||||
if(ret != 1)
|
||||
return(ret);
|
||||
|
||||
} else if(ret == -1) { /* non-AA field detected */
|
||||
was_non_aa= 1;
|
||||
|
||||
} else if(ret < 0) { /* other error */
|
||||
return(-3);
|
||||
|
||||
} else if(ret == 0) { /* first fetch pending pairs with num_data == 0 */
|
||||
/* should not happen, fetch more pairs */;
|
||||
|
||||
} else if(ret == 1) {
|
||||
/* name and value are not valid yet, submit more data */
|
||||
return(1);
|
||||
|
||||
} else if(ret == 2 || ret == 3 || ret == 4) {
|
||||
/* name and value are valid, submit more data */
|
||||
/* name and value are valid, pairs pending, fetch with num_data == 0 */
|
||||
/* name and value are valid, no more data expected */
|
||||
aaip->list_pending_pair= ret;
|
||||
|
||||
if(aaip->list_num_attrs >= aaip->list_size) {
|
||||
ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(char *),
|
||||
(char **) &(aaip->list_names), &(aaip->list_size), 1);
|
||||
if(ret != 1)
|
||||
return(ret);
|
||||
ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(char *),
|
||||
(char **) &(aaip->list_values), &(aaip->list_size), 1);
|
||||
if(ret != 1)
|
||||
return(ret);
|
||||
ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(size_t),
|
||||
(char **) &(aaip->list_value_lengths), &(aaip->list_size), 0);
|
||||
if(ret != 1)
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* Allocate name and value in list */;
|
||||
if(aaip->list_mem_used + aaip->name_buf_fill + aaip->value_buf_fill + 2
|
||||
> memory_limit) {
|
||||
return(3);
|
||||
}
|
||||
aaip->list_mem_used+= aaip->name_buf_fill + aaip->value_buf_fill + 2;
|
||||
i= aaip->list_num_attrs;
|
||||
aaip->list_names[i]= calloc(aaip->name_buf_fill + 1, 1);
|
||||
aaip->list_values[i]= calloc(aaip->value_buf_fill + 1, 1);
|
||||
memcpy(aaip->list_names[i], aaip->name_buf, aaip->name_buf_fill);
|
||||
aaip->list_names[i][aaip->name_buf_fill]= 0;
|
||||
memcpy(aaip->list_values[i], aaip->value_buf, aaip->value_buf_fill);
|
||||
aaip->list_values[i][aaip->value_buf_fill]= 0;
|
||||
aaip->list_value_lengths[i]= aaip->value_buf_fill;
|
||||
aaip->list_num_attrs++;
|
||||
aaip->name_buf_fill= aaip->value_buf_fill= 0;
|
||||
|
||||
aaip->list_pending_pair= 0;
|
||||
|
||||
if(ret == 2)
|
||||
return(1);
|
||||
if(ret == 4)
|
||||
break;
|
||||
|
||||
} else if(ret == 5)
|
||||
break;
|
||||
else
|
||||
return(-2);
|
||||
|
||||
num_data= 0; /* consume pending pairs */
|
||||
}
|
||||
aaip->list_pending_pair= 5;
|
||||
return(2);
|
||||
}
|
||||
|
||||
|
||||
/* 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 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
|
||||
@return <0 error
|
||||
0 no attribute list ready
|
||||
1 ok
|
||||
*/
|
||||
int aaip_get_decoded_attrs(struct aaip_state **handle, size_t *num_attrs,
|
||||
char ***names, size_t **value_lengths, char ***values,
|
||||
int flag)
|
||||
{
|
||||
size_t i;
|
||||
struct aaip_state *aaip;
|
||||
|
||||
aaip= *((struct aaip_state **) handle);
|
||||
if(flag & (1 << 15)) {
|
||||
if(*names != NULL) {
|
||||
for(i= 0; i < *num_attrs; i++) {
|
||||
if((*names)[i] != NULL)
|
||||
free((*names)[i]);
|
||||
(*names)[i]= NULL;
|
||||
}
|
||||
free(*names);
|
||||
*names= NULL;
|
||||
}
|
||||
if(*values != NULL) {
|
||||
for(i= 0; i < *num_attrs; i++) {
|
||||
if((*values)[i] != NULL)
|
||||
free((*values)[i]);
|
||||
(*values)[i]= NULL;
|
||||
}
|
||||
free(*values);
|
||||
*values= NULL;
|
||||
}
|
||||
if(*value_lengths != NULL)
|
||||
free(*value_lengths);
|
||||
*value_lengths= NULL;
|
||||
*num_attrs= 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Check whether decoding is finished yet */
|
||||
if(aaip->list_pending_pair != 5)
|
||||
return(0);
|
||||
|
||||
*num_attrs= aaip->list_num_attrs;
|
||||
*names= aaip->list_names;
|
||||
*value_lengths= aaip->list_value_lengths;
|
||||
*values= aaip->list_values;
|
||||
|
||||
/* Now the memory is owned by the caller */
|
||||
aaip->list_num_attrs= 0;
|
||||
aaip->list_names= NULL;
|
||||
aaip->list_value_lengths= NULL;
|
||||
aaip->list_values= NULL;
|
||||
aaip->list_size= 0;
|
||||
aaip->list_pending_pair= 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ------ Decoder for ACLs ------ */
|
||||
|
||||
|
||||
@ -1339,3 +1667,17 @@ int aaip_decode_acl(unsigned char *data, size_t num_data, size_t *consumed,
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------- Adapter for operating systems ----------------- */
|
||||
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
#include "aaip-os-freebsd.c"
|
||||
|
||||
#else
|
||||
|
||||
#include "aaip-os-linux.c"
|
||||
|
||||
#endif
|
||||
|
||||
|
181
test/aaip_0_2.h
181
test/aaip_0_2.h
@ -5,6 +5,7 @@
|
||||
Demonstration program for encoding and decoding EA and ACL.
|
||||
|
||||
See http://libburnia-project.org/wiki/AAIP
|
||||
or doc/susp_aaip_0_2.txt
|
||||
|
||||
test/aaip_0.2.h - Public declarations
|
||||
|
||||
@ -20,8 +21,8 @@
|
||||
@param aa_name The 2 byte SUSP Signature Word of the fields
|
||||
@param num_attrs Number of attributes
|
||||
@param names Array of pointers to 0 terminated name strings
|
||||
@param attr_lengths Array of byte lengths for each attribute payload
|
||||
@param attrs Array of pointers to the attribute payload bytes
|
||||
@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
|
||||
@ -33,10 +34,12 @@
|
||||
*/
|
||||
unsigned int aaip_encode(char aa_name[2],
|
||||
unsigned int num_attrs, char **names,
|
||||
size_t *attr_lengths, char **attrs,
|
||||
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 0.2 this value is to be stored together with
|
||||
an empty name.
|
||||
@ -55,14 +58,62 @@ int aaip_encode_acl(char *acl_text,
|
||||
size_t *result_len, unsigned char **result, 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
|
||||
bit15= free text and return 1
|
||||
@return > 0 ok
|
||||
-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 ACL attribute
|
||||
(e.g. system.posix_acl_access)
|
||||
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 avoids the use of dynamic memory. It rather provides a
|
||||
stateful decoding context with a small buffer which delivers results to
|
||||
caller provided memory locations.
|
||||
This may be done stream-like via the Component Level Interface or to
|
||||
fixly sized storage for name and value via the Pair Level Interface.
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
@ -79,17 +130,22 @@ size_t aaip_sizeof_aaip_state(void);
|
||||
/* Initialize a AAIP decoder context.
|
||||
This has to be done before the first AA 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 aa_name The Signature Word (advised is "AA")
|
||||
@param flag Bitfield for control purposes
|
||||
submit 0
|
||||
@return <=0 error , >0 ok
|
||||
*/
|
||||
int aaip_init(struct aaip_state *aaip, char aa_name[2], int flag);
|
||||
int aaip_init_aaip_state(struct aaip_state *aaip, char aa_name[2], int flag);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Component Level Interface
|
||||
/* ------------------------- 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 ransactions is virtually
|
||||
moderately sized result pieces. The number of transactions is virtually
|
||||
unlimited.
|
||||
*/
|
||||
|
||||
@ -148,8 +204,8 @@ int aaip_fetch_data(struct aaip_state *aaip,
|
||||
int aaip_skip_component(struct aaip_state *aaip, int flag);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Pair Level Interface
|
||||
/* ------------------------- 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.
|
||||
|
||||
@ -161,7 +217,7 @@ int aaip_skip_component(struct aaip_state *aaip, int flag);
|
||||
|
||||
|
||||
/* Accept raw input data and collect a pair of name and value.
|
||||
The return value iwill indicate whether the pair is complete, whether more
|
||||
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.
|
||||
@ -200,6 +256,65 @@ int aaip_decode_pair(struct aaip_state *aaip,
|
||||
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 aa_name The Signature Word (advised is "AA")
|
||||
@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, char aa_name[2],
|
||||
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 0.2 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
|
||||
@ -226,5 +341,41 @@ int aaip_decode_acl(unsigned char *data, size_t num_data, size_t *consumed,
|
||||
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
|
||||
-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 ACL attribute
|
||||
(e.g. system.posix_acl_access)
|
||||
@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
|
||||
|
||||
*/
|
||||
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 */
|
||||
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
test/aaip_0_2_test.c - Main program for test binary
|
||||
|
||||
Compile: cc -g -Wall -o test/aaip test/aaip_0_2.c test/aaip_0_2_test.c -lacl
|
||||
Compile:
|
||||
cc -g -Wall -o test/aaip test/aaip_0_2.c test/aaip_0_2_test.c -lacl
|
||||
|
||||
Usage: ./aaip name value
|
||||
Long parameters ./aaip -name"x100" -value"x100"
|
||||
@ -57,14 +58,56 @@ static int print_result(unsigned char *result, size_t result_len, int flag)
|
||||
}
|
||||
|
||||
|
||||
static int print_attrs(size_t num_attrs, char **names, size_t *value_lengths,
|
||||
char **values, int flag)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for(i= 0; i < num_attrs; i++) {
|
||||
printf("name='");
|
||||
for(j= 0; names[i][j] != 0; j++) {
|
||||
if(names[i][j] >= 32 && names[i][j] <= 126 &&
|
||||
names[i][j] != '\\' && names[i][j] != '\'')
|
||||
printf("%c", names[i][j]);
|
||||
else
|
||||
printf("\\%o", (unsigned int) ((unsigned char **) names)[i][j]);
|
||||
}
|
||||
printf("' (%d)\n", (int) j);
|
||||
printf("value='");
|
||||
for(j= 0; j < value_lengths[i]; j++) {
|
||||
if(values[i][j] >= 32 && values[i][j] <= 126 &&
|
||||
values[i][j] != '\\' && values[i][j] != '\'')
|
||||
printf("%c", values[i][j]);
|
||||
else
|
||||
printf("\\%3.3o", (unsigned int) ((unsigned char **) values)[i][j]);
|
||||
}
|
||||
printf("' (%d)\n\n", (int) j);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int do_touch(char *path, int flag)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp= fopen(path, "a");
|
||||
if(fp == NULL) {
|
||||
fprintf(stderr, "fopen(\"%s\") failed: %d %s\n",
|
||||
path, errno, errno != 0 ? strerror(errno) : "");
|
||||
return(0);
|
||||
}
|
||||
fclose(fp);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int decode_acl(unsigned char *result, size_t result_len,
|
||||
char *out_path, int flag)
|
||||
{
|
||||
int ret;
|
||||
size_t consumed, text_fill;
|
||||
char *text= NULL;
|
||||
acl_t out_acl= NULL;
|
||||
FILE *fp;
|
||||
|
||||
ret= aaip_decode_acl(result, result_len, &consumed, NULL, 0, &text_fill, 1);
|
||||
if(ret <= 0) {
|
||||
@ -83,30 +126,21 @@ static int decode_acl(unsigned char *result, size_t result_len,
|
||||
if(out_path == NULL)
|
||||
{ret= 1; goto ex;}
|
||||
|
||||
out_acl= acl_from_text(text);
|
||||
if(out_acl == NULL) {
|
||||
fprintf(stderr, "acl_from_text failed: %d %s\n",
|
||||
errno, errno != 0 ? strerror(errno) : "");
|
||||
ret= 0; goto ex;
|
||||
}
|
||||
fp= fopen(out_path, "a");
|
||||
if(fp == NULL) {
|
||||
fprintf(stderr, "fopen(\"%s\") failed: %d %s\n",
|
||||
out_path, errno, errno != 0 ? strerror(errno) : "");
|
||||
ret= 0; goto ex;
|
||||
}
|
||||
fclose(fp);
|
||||
ret= do_touch(out_path, 0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
|
||||
ret= acl_set_file(out_path, ACL_TYPE_ACCESS, out_acl);
|
||||
if(ret == -1) {
|
||||
fprintf(stderr, "acl_set_file(\"%s\") failed: %d %s\n",
|
||||
out_path, errno, errno != 0 ? strerror(errno) : "");
|
||||
ret= aaip_set_acl_text(out_path, text, 0);
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "aaip_set_acl_text() failed");
|
||||
if(ret == -1)
|
||||
fprintf(stderr, ": %d %s\n", errno, errno != 0 ? strerror(errno) : "");
|
||||
else
|
||||
fprintf(stderr, "\n");
|
||||
ret= 0; goto ex;
|
||||
}
|
||||
ret= 1;
|
||||
ex:
|
||||
if(out_acl != NULL)
|
||||
acl_free(out_acl);
|
||||
if(text != NULL)
|
||||
free(text);
|
||||
return(ret);
|
||||
@ -116,58 +150,52 @@ ex:
|
||||
static int test_acl(char *in_path, char *out_path, int flag)
|
||||
{
|
||||
int ret;
|
||||
acl_t acl= NULL;
|
||||
char *acl_text= NULL;
|
||||
unsigned char *result= NULL;
|
||||
size_t result_len;
|
||||
|
||||
acl= acl_get_file(in_path, ACL_TYPE_ACCESS);
|
||||
if(acl == NULL) {
|
||||
fprintf(stderr, "acl_get_file failed: %d %s\n",
|
||||
errno, errno != 0 ? strerror(errno) : "");
|
||||
ret= 0; goto ex;
|
||||
}
|
||||
acl_text= acl_to_text(acl, NULL);
|
||||
if(acl_text == NULL) {
|
||||
fprintf(stderr, "acl_to_text failed: %d %s\n",
|
||||
errno, errno != 0 ? strerror(errno) : "");
|
||||
ret= 0; goto ex;
|
||||
ret= aaip_get_acl_text(in_path, &acl_text, 0);
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "aaip_get_acl_text() failed");
|
||||
if(ret == -1)
|
||||
fprintf(stderr, ": %d %s\n", errno, errno != 0 ? strerror(errno) : "");
|
||||
else
|
||||
fprintf(stderr, "\n");
|
||||
ret= 6; goto ex;
|
||||
}
|
||||
printf("--- ACL:\n%s--- end of ACL\n\n", acl_text);
|
||||
|
||||
ret= aaip_encode_acl(acl_text, &result_len, &result, 0);
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "aaip_encode_acl(text) failed: ret= %d\n", ret);
|
||||
ret= 0; goto ex;
|
||||
ret= 7; goto ex;
|
||||
}
|
||||
print_result(result, result_len, 0);
|
||||
ret= decode_acl(result, result_len, out_path, 0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
{ret= 8; goto ex;}
|
||||
free(result); result= NULL;
|
||||
|
||||
ret= aaip_encode_acl(acl_text, &result_len, &result, 2);
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "aaip_encode_acl(num) failed: ret= %d\n", ret);
|
||||
ret= 0; goto ex;
|
||||
ret= 9; goto ex;
|
||||
}
|
||||
print_result(result, result_len, 0);
|
||||
ret= decode_acl(result, result_len, out_path, 0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
{ret= 10; goto ex;}
|
||||
|
||||
ret= 1;
|
||||
ret= 0;
|
||||
ex:;
|
||||
if(acl_text != NULL)
|
||||
acl_free(acl_text);
|
||||
if(acl != NULL)
|
||||
acl_free(acl);
|
||||
aaip_get_acl_text("", &acl_text, 1 << 15);
|
||||
if(result != NULL)
|
||||
free(result);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
||||
int synthetic_pairs(char *prog, int argc, char **argv, int flag)
|
||||
{
|
||||
int ret, l, mult= 0, k;
|
||||
size_t result_len, i;
|
||||
@ -186,39 +214,31 @@ int main(int argc, char **argv)
|
||||
unsigned char *rpt;
|
||||
unsigned int skipped, was_skipped= 0;
|
||||
|
||||
|
||||
test_acl("/u/test/acl", "/u/test/out_acl", 0);
|
||||
|
||||
|
||||
if(argc < 3 || (argc % 2) == 0) {
|
||||
fprintf(stderr, "usage: %s [-]name[xNNN] [-]value[xNNN] ...\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
aaip= (struct aaip_state *) calloc(aaip_sizeof_aaip_state(), 1);
|
||||
names= calloc(sizeof(char *), (argc - 1) / 2);
|
||||
values= calloc(sizeof(char *), (argc - 1) / 2);
|
||||
value_lengths= calloc(sizeof(size_t), (argc - 1) / 2);
|
||||
names= calloc(sizeof(char *), argc / 2);
|
||||
values= calloc(sizeof(char *), argc / 2);
|
||||
value_lengths= calloc(sizeof(size_t), argc / 2);
|
||||
|
||||
for(i= 0; i < argc - 1; i++) {
|
||||
for(i= 0; i < argc; i++) {
|
||||
if(i % 2)
|
||||
param= values + i / 2;
|
||||
else
|
||||
param= names + i / 2;
|
||||
(*param)= argv[i + 1];
|
||||
if(argv[i + 1][0] == '-') {
|
||||
cpt= strchr(argv[i + 1], 'x');
|
||||
(*param)= argv[i];
|
||||
if(argv[i][0] == '-') {
|
||||
cpt= strchr(argv[i], 'x');
|
||||
if(cpt != NULL) {
|
||||
l= cpt - argv[i + 1] - 1;
|
||||
l= cpt - argv[i] - 1;
|
||||
if(l > 0)
|
||||
sscanf(cpt + 1, "%d", &mult);
|
||||
if(l > 0 && mult > 0) {
|
||||
(*param)= calloc(1, l * mult + 1);
|
||||
if((*param) != NULL) {
|
||||
for(k= 0; k < mult; k++)
|
||||
memcpy((*param) + k * l, argv[i + 1] + 1, l);
|
||||
memcpy((*param) + k * l, argv[i] + 1, l);
|
||||
(*param)[mult * l]= 0;
|
||||
} else
|
||||
(*param)= argv[i + 1];
|
||||
(*param)= argv[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -226,16 +246,16 @@ int main(int argc, char **argv)
|
||||
value_lengths[i / 2]= strlen(values[i / 2]);
|
||||
}
|
||||
|
||||
ret= aaip_encode("AA", (unsigned int) ((argc - 1) / 2), names,
|
||||
ret= aaip_encode("AA", (unsigned int) (argc / 2), names,
|
||||
value_lengths, values,
|
||||
&result_len, &result, 0);
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "%s : aaip_encode failed with ret= %d\n", argv[0], ret);
|
||||
exit(2);
|
||||
fprintf(stderr, "%s : aaip_encode failed with ret= %d\n", prog, ret);
|
||||
return(2);
|
||||
}
|
||||
print_result(result, result_len, 0);
|
||||
|
||||
aaip_init(aaip, "AA", 0);
|
||||
aaip_init_aaip_state(aaip, "AA", 0);
|
||||
rpt= result;
|
||||
submit_data= 1;
|
||||
is_done= 0;
|
||||
@ -246,8 +266,8 @@ int main(int argc, char **argv)
|
||||
todo= 2048;
|
||||
if(todo == 0) {
|
||||
fprintf(stderr, "%s : Out of data while still prompted to submit\n",
|
||||
argv[0]);
|
||||
exit(5);
|
||||
prog);
|
||||
return(5);
|
||||
}
|
||||
} else
|
||||
todo= 0;
|
||||
@ -261,9 +281,8 @@ int main(int argc, char **argv)
|
||||
was_skipped= skipped;
|
||||
}
|
||||
if(ret < 0) {
|
||||
fprintf(stderr, "%s : aaip_decode_pair failed with ret= %d\n",
|
||||
argv[0], ret);
|
||||
exit(3);
|
||||
fprintf(stderr, "%s : aaip_decode_pair failed with ret= %d\n", prog, ret);
|
||||
return(3);
|
||||
}
|
||||
rpt+= todo;
|
||||
if(ret == 0) {
|
||||
@ -284,8 +303,8 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
} else {
|
||||
fprintf(stderr, "%s : Unknown return %d from aaip_decode_pair()\n",
|
||||
argv[0], ret);
|
||||
exit(4);
|
||||
prog, ret);
|
||||
return(4);
|
||||
}
|
||||
name[name_fill]= 0;
|
||||
value[value_fill]= 0;
|
||||
@ -299,7 +318,126 @@ int main(int argc, char **argv)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@param flag bit0= use numeric qualifiers
|
||||
*/
|
||||
static int copy_all(char *in_path, char *out_path, int flag)
|
||||
{
|
||||
int ret;
|
||||
struct aaip_state *aaip= NULL;
|
||||
size_t in_num_attrs, *in_value_lengths= NULL;
|
||||
char **in_names= NULL, **in_values= NULL;
|
||||
int is_done= 0, first_round= 1;
|
||||
unsigned char *result= NULL, *rpt;
|
||||
size_t result_len, todo, consumed;
|
||||
size_t out_num_attrs, *out_value_lengths= NULL;
|
||||
char **out_names= NULL, **out_values= NULL;
|
||||
|
||||
ret= aaip_get_attr_list(in_path, &in_num_attrs, &in_names, &in_value_lengths,
|
||||
&in_values, 1 | ((flag & 1) << 1));
|
||||
if(ret <= 0)
|
||||
{ret= 11; goto ex;}
|
||||
print_attrs(in_num_attrs, in_names, in_value_lengths, in_values, 0);
|
||||
|
||||
ret= aaip_encode("AA", (unsigned int) in_num_attrs, in_names,
|
||||
in_value_lengths, in_values, &result_len, &result, 0);
|
||||
if(ret == 0)
|
||||
{ret= 12; goto ex;}
|
||||
|
||||
if(result_len <= 0) {
|
||||
fprintf(stderr, "No result\n");
|
||||
ret= 13; goto ex;
|
||||
}
|
||||
print_result(result, result_len, 0);
|
||||
|
||||
rpt= result;
|
||||
while(!is_done) {
|
||||
todo= result_len - (rpt - result);
|
||||
if(todo > 2048)
|
||||
todo= 2048;
|
||||
if(todo == 0) {
|
||||
fprintf(stderr, "Out of data while still prompted to submit\n");
|
||||
ret= 14; goto ex;
|
||||
}
|
||||
/* 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;
|
||||
fprintf(stderr, "aaip_decode_attrs() returns %d\n", ret);
|
||||
ret= 15; goto ex;
|
||||
}
|
||||
if(rpt - result != result_len) {
|
||||
fprintf(stderr, "aaip_decode_attrs() returns 2 but %d bytes are left\n",
|
||||
(int) (result_len - (rpt - result)));
|
||||
ret= 16; goto ex;
|
||||
}
|
||||
ret= aaip_get_decoded_attrs(&aaip, &out_num_attrs, &out_names,
|
||||
&out_value_lengths, &out_values, 0);
|
||||
|
||||
if(ret != 1) {
|
||||
fprintf(stderr, "aaip_get_decoded_attrs() returns %d\n", ret);
|
||||
ret= 17; goto ex;
|
||||
}
|
||||
print_attrs(out_num_attrs, out_names, out_value_lengths, out_values, 0);
|
||||
|
||||
ret= do_touch(out_path, 0);
|
||||
if(ret <= 0)
|
||||
{ret= 19; goto ex;}
|
||||
|
||||
ret= aaip_set_attr_list(out_path, out_num_attrs, out_names, out_value_lengths,
|
||||
out_values, 1 | 2);
|
||||
if(ret != 1) {
|
||||
fprintf(stderr, "aaip_set_attr_list() returns %d\n", ret);
|
||||
ret= 18; goto ex;
|
||||
}
|
||||
ret= 0;
|
||||
ex:;
|
||||
if(in_names != NULL || in_value_lengths != NULL || in_values != NULL)
|
||||
aaip_get_attr_list(in_path, &in_num_attrs, &in_names, &in_value_lengths,
|
||||
&in_values, 1 << 15);
|
||||
if(out_names != NULL || out_value_lengths != NULL || out_values != NULL)
|
||||
aaip_get_decoded_attrs(&aaip, &out_num_attrs, &out_names,
|
||||
&out_value_lengths, &out_values, 15);
|
||||
aaip_decode_attrs(&aaip, "AA", (size_t) 0, (size_t) 0, NULL, (size_t) 0,
|
||||
&consumed, 1 << 15);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(argc < 2) {
|
||||
usage:
|
||||
fprintf(stderr, "usage : %s options\n", argv[0]);
|
||||
fprintf(stderr, " -pairs [-]name[xNNN] [-]value[xNNN] [...]\n");
|
||||
fprintf(stderr, " -copy_acl source_path target_path\n");
|
||||
fprintf(stderr, " -copy source_path target_path\n");
|
||||
exit(1);
|
||||
}
|
||||
if(strcmp(argv[1], "-pairs") == 0) {
|
||||
if(argc < 4 || (argc % 2) != 0)
|
||||
goto usage;
|
||||
ret= synthetic_pairs(argv[0], argc - 2, argv + 2, 0);
|
||||
} else if(strcmp(argv[1], "-copy_acl") == 0) {
|
||||
if(argc != 4)
|
||||
goto usage;
|
||||
ret= test_acl(argv[2], argv[3], 0);
|
||||
} else if(strcmp(argv[1], "-copy") == 0) {
|
||||
if(argc != 4)
|
||||
goto usage;
|
||||
ret= copy_all(argv[2], argv[3], 1);
|
||||
} else
|
||||
goto usage;
|
||||
exit(ret);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user