1#include "EXTERN.h"
2#include "perl.h"
3#include "XSUB.h"
4
5#include "ppport.h"
6#include "portable.h"
7
8
9#define MAX_INITIAL_VALUELEN_VARNAME "File::ExtAttr::MAX_INITIAL_VALUELEN"
10                                        /* Richard, fixme! */
11
12
13MODULE = File::ExtAttr        PACKAGE = File::ExtAttr
14
15PROTOTYPES: ENABLE
16
17
18int
19_setfattr (path, attrname, attrvalueSV, flags = 0)
20         const char *path
21         const char *attrname
22         SV * attrvalueSV
23         HV * flags
24    PREINIT:
25        STRLEN slen;
26        char * attrvalue;
27        int rc;
28
29    CODE:
30        attrvalue = SvPV(attrvalueSV, slen);
31        rc = portable_setxattr(path, attrname, attrvalue, slen, flags);
32        if (rc < 0)
33          errno = -rc;
34        RETVAL = (rc == 0);
35
36    OUTPUT:
37        RETVAL
38
39
40int
41_fsetfattr (fd, attrname, attrvalueSV, flags = 0)
42         int fd
43         const char *attrname
44         SV * attrvalueSV
45         HV * flags
46    PREINIT:
47        STRLEN slen;
48        char * attrvalue;
49        int rc;
50
51    CODE:
52        attrvalue = SvPV(attrvalueSV, slen);
53        rc = portable_fsetxattr(fd, attrname, attrvalue, slen, flags);
54        if (rc < 0)
55          errno = -rc;
56        RETVAL = (rc == 0);
57
58    OUTPUT:
59        RETVAL
60
61
62SV *
63_getfattr(path, attrname, flags = 0)
64        const char *path
65        const char *attrname
66        HV * flags
67   PREINIT:
68        char * attrvalue;
69        int attrlen;
70        ssize_t buflen;
71
72   CODE:
73        buflen = portable_lenxattr(path, attrname, flags);
74        if (buflen <= 0)
75	  buflen = SvIV(get_sv(MAX_INITIAL_VALUELEN_VARNAME, FALSE));
76
77        attrvalue = NULL;
78        Newz(1, attrvalue, buflen, char);
79
80        attrlen = portable_getxattr(path, attrname, attrvalue, buflen, flags);
81        if (attrlen < 0){
82
83            //key not found, just return undef
84            if(errno == ENOATTR){
85                Safefree(attrvalue);
86                errno = -attrlen;
87                XSRETURN_UNDEF;
88
89            //return undef
90            }else{
91                Safefree(attrvalue);
92                errno = -attrlen;
93                XSRETURN_UNDEF;
94            }
95        }
96
97        RETVAL = newSVpv(attrvalue, attrlen);
98        Safefree(attrvalue);
99
100    OUTPUT:
101        RETVAL
102
103
104SV *
105_fgetfattr(fd, attrname, flags = 0)
106        int fd
107        const char *attrname
108        HV * flags
109   PREINIT:
110        char * attrvalue;
111        int attrlen;
112        ssize_t buflen;
113
114   CODE:
115        buflen = portable_flenxattr(fd, attrname, flags);
116        if (buflen <= 0)
117	  buflen = SvIV(get_sv(MAX_INITIAL_VALUELEN_VARNAME, FALSE));
118
119        attrvalue = NULL;
120        Newz(1, attrvalue, buflen, char);
121
122        attrlen = portable_fgetxattr(fd, attrname, attrvalue, buflen, flags);
123        if (attrlen < 0){
124
125            //key not found, just return undef
126            if(errno == ENOATTR){
127                Safefree(attrvalue);
128                errno = -attrlen;
129                XSRETURN_UNDEF;
130
131            //return undef
132            }else{
133                Safefree(attrvalue);
134                errno = -attrlen;
135                XSRETURN_UNDEF;
136            }
137        }
138
139        RETVAL = newSVpv(attrvalue, attrlen);
140        Safefree(attrvalue);
141
142    OUTPUT:
143        RETVAL
144
145
146int
147_delfattr (path, attrname, flags = 0)
148        const char *path
149        const char *attrname
150        HV * flags
151    PREINIT:
152        int rc;
153
154    CODE:
155        rc = portable_removexattr(path, attrname, flags);
156        if (rc < 0)
157          errno = -rc;
158        RETVAL = (rc == 0);
159
160    OUTPUT:
161        RETVAL
162
163
164int
165_fdelfattr (fd, attrname, flags = 0)
166        int fd
167        const char *attrname
168        HV * flags
169    PREINIT:
170        int rc;
171
172    CODE:
173        rc = portable_fremovexattr(fd, attrname, flags);
174        if (rc < 0)
175          errno = -rc;
176        RETVAL = (rc == 0);
177
178    OUTPUT:
179        RETVAL
180
181void
182_listfattr (path, fd, flags = 0)
183        const char *path
184        int fd
185        HV * flags
186    PREINIT:
187        ssize_t size, ret;
188        char *namebuf = NULL;
189        char *nameptr;
190
191    PPCODE:
192        if(fd == -1)
193            size = portable_listxattr(path, NULL, 0, flags);
194        else
195            size = portable_flistxattr(fd, NULL, 0, flags);
196
197        if (size < 0)
198        {
199            errno = -(int) size;
200            XSRETURN_UNDEF;
201        } else if (size == 0)
202        {
203            XSRETURN_EMPTY;
204        }
205
206        namebuf = malloc(size);
207
208        if (fd == -1)
209            ret = portable_listxattr(path, namebuf, size, flags);
210        else
211            ret = portable_flistxattr(fd, namebuf, size, flags);
212
213        // There could be a race condition here, if someone adds a new
214        // attribute between the two listxattr calls. However it just means we
215        // might return ERANGE.
216
217        if (ret < 0)
218        {
219            free(namebuf);
220            errno = -ret;
221            XSRETURN_UNDEF;
222        } else if (ret == 0)
223        {
224            free(namebuf);
225            XSRETURN_EMPTY;
226        }
227
228        nameptr = namebuf;
229
230        while(nameptr < namebuf + ret)
231        {
232          char *endptr = nameptr;
233          while(*endptr++ != '\0');
234
235          // endptr will now point one past the end..
236
237          XPUSHs(sv_2mortal(newSVpvn(nameptr, endptr - nameptr - 1)));
238
239          // nameptr could now point past the end of namebuf
240          nameptr = endptr;
241        }
242
243        free(namebuf);
244
245void
246_listfattrns (path, fd, flags = 0)
247        const char *path
248        int fd
249        HV * flags
250    PREINIT:
251        ssize_t size, ret;
252        char *namebuf = NULL;
253        char *nameptr;
254
255    PPCODE:
256        if(fd == -1)
257            size = portable_listxattrns(path, NULL, 0, flags);
258        else
259            size = portable_flistxattrns(fd, NULL, 0, flags);
260
261        if (size < 0)
262        {
263            errno = -(int) size;
264            XSRETURN_UNDEF;
265        } else if (size == 0)
266        {
267            XSRETURN_EMPTY;
268        }
269
270        namebuf = malloc(size);
271
272        if (fd == -1)
273            ret = portable_listxattrns(path, namebuf, size, flags);
274        else
275            ret = portable_flistxattrns(fd, namebuf, size, flags);
276
277        // There could be a race condition here, if someone adds a new
278        // attribute between the two listxattr calls. However it just means we
279        // might return ERANGE.
280
281        if (ret < 0)
282        {
283            free(namebuf);
284            errno = -ret;
285            XSRETURN_UNDEF;
286        } else if (ret == 0)
287        {
288            free(namebuf);
289            XSRETURN_EMPTY;
290        }
291
292        nameptr = namebuf;
293
294        while(nameptr < namebuf + ret)
295        {
296          char *endptr = nameptr;
297          while(*endptr++ != '\0');
298
299          // endptr will now point one past the end..
300
301          XPUSHs(sv_2mortal(newSVpvn(nameptr, endptr - nameptr - 1)));
302
303          // nameptr could now point past the end of namebuf
304          nameptr = endptr;
305        }
306
307        free(namebuf);
308