]> arthur.barton.de Git - netatalk.git/blob - libatalk/adouble/ad_flush.c
First working adouble:ea->osx fallback working
[netatalk.git] / libatalk / adouble / ad_flush.c
1 /*
2  * Copyright (c) 1990,1991 Regents of The University of Michigan.
3  * Copyright (c) 2010      Frank Lahm
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software and
7  * its documentation for any purpose and without fee is hereby granted,
8  * provided that the above copyright notice appears in all copies and
9  * that both that copyright notice and this permission notice appear
10  * in supporting documentation, and that the name of The University
11  * of Michigan not be used in advertising or publicity pertaining to
12  * distribution of the software without specific, written prior
13  * permission. This software is supplied as is without expressed or
14  * implied warranties of any kind.
15  *
16  *  Research Systems Unix Group
17  *  The University of Michigan
18  *  c/o Mike Clark
19  *  535 W. William Street
20  *  Ann Arbor, Michigan
21  *  +1-313-763-0525
22  *  netatalk@itd.umich.edu
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif /* HAVE_CONFIG_H */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <arpa/inet.h>
34
35 #include <atalk/adouble.h>
36 #include <atalk/ea.h>
37 #include <atalk/logger.h>
38 #include <atalk/bstrlib.h>
39 #include <atalk/bstradd.h>
40 #include <atalk/errchk.h>
41
42 #include "ad_lock.h"
43
44 static const uint32_t set_eid[] = {
45     0,1,2,3,4,5,6,7,8,
46     9,10,11,12,13,14,15,
47     AD_DEV, AD_INO, AD_SYN, AD_ID
48 };
49
50 #define EID_DISK(a) (set_eid[a])
51
52 /*
53  * Prepare ad->ad_data buffer from struct adouble for writing on disk
54  */
55 int ad_rebuild_adouble_header(struct adouble *ad)
56 {
57     uint32_t       eid;
58     uint32_t       temp;
59     uint16_t       nent;
60     char        *buf, *nentp;
61     int             len;
62
63     buf = ad->ad_data;
64
65     temp = htonl( ad->ad_magic );
66     memcpy(buf, &temp, sizeof( temp ));
67     buf += sizeof( temp );
68
69     temp = htonl( ad->ad_version );
70     memcpy(buf, &temp, sizeof( temp ));
71     buf += sizeof( temp );
72
73     buf += sizeof( ad->ad_filler );
74
75     nentp = buf;
76     buf += sizeof( nent );
77     for ( eid = 0, nent = 0; eid < ADEID_MAX; eid++ ) {
78         if ( ad->ad_eid[ eid ].ade_off == 0 ) {
79             continue;
80         }
81         temp = htonl( EID_DISK(eid) );
82         memcpy(buf, &temp, sizeof( temp ));
83         buf += sizeof( temp );
84
85         temp = htonl( ad->ad_eid[ eid ].ade_off );
86         memcpy(buf, &temp, sizeof( temp ));
87         buf += sizeof( temp );
88
89         temp = htonl( ad->ad_eid[ eid ].ade_len );
90         memcpy(buf, &temp, sizeof( temp ));
91         buf += sizeof( temp );
92         nent++;
93     }
94     nent = htons( nent );
95     memcpy(nentp, &nent, sizeof( nent ));
96
97     switch (ad->ad_vers) {
98     case AD_VERSION2:
99         len = ad_getentryoff(ad, ADEID_RFORK);
100         break;
101     case AD_VERSION_EA:
102         len = AD_DATASZ_EA;
103         break;
104     default:
105         LOG(log_error, logtype_afpd, "Unexpected adouble version");
106         len = 0;
107         break;
108     }
109
110     return len;
111 }
112
113 /*!
114  * Prepare adbuf buffer from struct adouble for writing on disk
115  */
116 static int ad_rebuild_adouble_header_osx(struct adouble *ad, char *adbuf)
117 {
118     uint32_t       temp;
119     uint16_t       nent;
120     char           *buf;
121     int            len;
122
123     LOG(log_debug, logtype_default, "ad_rebuild_adouble_header_osx");
124
125     buf = &adbuf[0];
126
127     temp = htonl( ad->ad_magic );
128     memcpy(buf, &temp, sizeof( temp ));
129     buf += sizeof( temp );
130
131     temp = htonl( ad->ad_version );
132     memcpy(buf, &temp, sizeof( temp ));
133     buf += sizeof( temp );
134
135     buf += sizeof( ad->ad_filler );
136
137     nent = htons(ADEID_NUM_OSX);
138     memcpy(buf, &nent, sizeof( nent ));
139     buf += sizeof( nent );
140
141     /* FinderInfo */
142     temp = htonl(EID_DISK(ADEID_FINDERI));
143     memcpy(buf, &temp, sizeof( temp ));
144     buf += sizeof( temp );
145
146     temp = htonl(ADEDOFF_FINDERI_OSX);
147     memcpy(buf, &temp, sizeof( temp ));
148     buf += sizeof( temp );
149
150     temp = htonl(ADEDLEN_FINDERI);
151     memcpy(buf, &temp, sizeof( temp ));
152     buf += sizeof( temp );
153
154     memcpy(adbuf + ADEDOFF_FINDERI_OSX, ad_entry(ad, ADEID_FINDERI), ADEDLEN_FINDERI);
155
156     /* rfork */
157     temp = htonl( EID_DISK(ADEID_RFORK) );
158     memcpy(buf, &temp, sizeof( temp ));
159     buf += sizeof( temp );
160
161     temp = htonl(ADEDOFF_RFORK_OSX);
162     memcpy(buf, &temp, sizeof( temp ));
163     buf += sizeof( temp );
164
165     temp = htonl( ad->ad_rlen);
166     memcpy(buf, &temp, sizeof( temp ));
167     buf += sizeof( temp );
168
169     return AD_DATASZ_OSX;
170 }
171
172 /* -------------------
173  * XXX copy only header with same size or comment
174  * doesn't work well for adouble with different version.
175  *
176  */
177 int ad_copy_header(struct adouble *add, struct adouble *ads)
178 {
179     uint32_t       eid;
180     uint32_t       len;
181
182     for ( eid = 0; eid < ADEID_MAX; eid++ ) {
183         if ( ads->ad_eid[ eid ].ade_off == 0 ) {
184             continue;
185         }
186
187         if ( add->ad_eid[ eid ].ade_off == 0 ) {
188             continue;
189         }
190
191         len = ads->ad_eid[ eid ].ade_len;
192         if (!len) {
193             continue;
194         }
195
196         if (eid != ADEID_COMMENT && add->ad_eid[ eid ].ade_len != len ) {
197             continue;
198         }
199
200         ad_setentrylen( add, eid, len );
201         memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len );
202     }
203     add->ad_rlen = ads->ad_rlen;
204     return 0;
205 }
206
207 static int ad_flush_hf(struct adouble *ad)
208 {
209     int len;
210
211     LOG(log_debug, logtype_default, "ad_flush_hf(%s)", adflags2logstr(ad->ad_adflags));
212
213     struct ad_fd *adf;
214
215     switch (ad->ad_vers) {
216     case AD_VERSION2:
217         adf = ad->ad_mdp;
218         break;
219     case AD_VERSION_EA:
220         adf = &ad->ad_data_fork;
221         break;
222     default:
223         LOG(log_error, logtype_afpd, "ad_flush: unexpected adouble version");
224         return -1;
225     }
226
227     if ((adf->adf_flags & O_RDWR)) {
228         if (ad_getentryoff(ad, ADEID_RFORK)) {
229             if (ad->ad_rlen > 0xffffffff)
230                 ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
231             else
232                 ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
233         }
234         len = ad->ad_ops->ad_rebuild_header(ad);
235
236         switch (ad->ad_vers) {
237         case AD_VERSION2:
238             if (adf_pwrite(ad->ad_mdp, ad->ad_data, len, 0) != len) {
239                 if (errno == 0)
240                     errno = EIO;
241                 return( -1 );
242             }
243             break;
244         case AD_VERSION_EA:
245             if (AD_META_OPEN(ad)) {
246                 if (sys_fsetxattr(ad_data_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) != 0) {
247                     LOG(log_error, logtype_afpd, "ad_flush: sys_fsetxattr error: %s",
248                         strerror(errno));
249                     return -1;
250                 }
251             }
252             break;
253         default:
254             LOG(log_error, logtype_afpd, "ad_flush: unexpected adouble version");
255             return -1;
256         }
257     }
258
259     return( 0 );
260 }
261
262 /* Flush resofork adouble file if any (currently adouble:ea and #ifndef HAVE_EAFD eg Linux) */
263 static int ad_flush_rf(struct adouble *ad)
264 {
265     ssize_t len;
266     char    adbuf[AD_DATASZ_OSX];
267
268 #ifdef HAVE_EAFD
269     return 0;
270 #endif
271     if (ad->ad_vers != AD_VERSION_EA)
272         return 0;
273
274     LOG(log_debug, logtype_default, "ad_flush_rf(%s)", adflags2logstr(ad->ad_adflags));
275
276     if ((ad->ad_rfp->adf_flags & O_RDWR)) {
277         if (ad_getentryoff(ad, ADEID_RFORK)) {
278             if (ad->ad_rlen > 0xffffffff)
279                 ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
280             else
281                 ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
282         }
283         len = ad_rebuild_adouble_header_osx(ad, &adbuf[0]);
284
285         if (adf_pwrite(ad->ad_rfp, adbuf, len, 0) != len) {
286             if (errno == 0)
287                 errno = EIO;
288             return -1;
289         }
290     }
291     return 0;
292 }
293
294 int ad_flush(struct adouble *ad)
295 {
296     EC_INIT;
297
298     LOG(log_debug, logtype_default, "ad_flush(%s)", adflags2logstr(ad->ad_adflags));
299
300     if (AD_META_OPEN(ad)) {
301         EC_ZERO( ad_flush_hf(ad) );
302     }
303
304     if (AD_RSRC_OPEN(ad)) {
305         EC_ZERO( ad_flush_rf(ad) );
306     }
307
308 EC_CLEANUP:
309     EC_EXIT;
310 }
311
312 static int ad_data_closefd(struct adouble *ad)
313 {
314     int ret = 0;
315
316     if (ad_data_fileno(ad) == -2) {
317         free(ad->ad_data_fork.adf_syml);
318         ad->ad_data_fork.adf_syml = NULL;
319     } else {
320         if (close(ad_data_fileno(ad)) < 0)
321             ret = -1;
322     }
323     ad_data_fileno(ad) = -1;
324     return ret;
325 }
326
327 /*!
328  * Close a struct adouble freeing all resources
329  */
330 int ad_close(struct adouble *ad, int adflags)
331 {
332     int err = 0;
333
334     if (ad == NULL)
335         return err;
336
337     LOG(log_debug, logtype_default, "ad_close(%s)", adflags2logstr(adflags));
338
339     /* cf ad_open(): we opened the datafork too for sharemode locks */
340     if ((ad->ad_vers == AD_VERSION_EA) && (ad->ad_adflags & ADFLAGS_SETSHRMD))
341         adflags |= ADFLAGS_DF;
342
343     if ((adflags & ADFLAGS_DF)
344         && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == -2) /* -2 means symlink */
345         && --ad->ad_data_fork.adf_refcount == 0) {
346         if (ad_data_closefd(ad) < 0)
347             err = -1;
348         adf_lock_free(&ad->ad_data_fork);
349     }
350
351     if ((adflags & ADFLAGS_HF)
352         && (ad_meta_fileno(ad) != -1) && !(--ad->ad_mdp->adf_refcount)) {
353         if (close( ad_meta_fileno(ad)) < 0)
354             err = -1;
355         ad_meta_fileno(ad) = -1;
356         if (ad->ad_vers == AD_VERSION2)
357             adf_lock_free(ad->ad_mdp);
358     }
359
360     if ((adflags & ADFLAGS_RF) && (ad->ad_vers == AD_VERSION_EA)) {
361         if ((ad_reso_fileno(ad) != -1)
362             && !(--ad->ad_rfp->adf_refcount)) {
363             if (close(ad->ad_rfp->adf_fd) < 0)
364                 err = -1;
365             ad->ad_rlen = 0;
366             ad_reso_fileno(ad) = -1;
367         }
368     }
369
370     return err;
371 }