]> arthur.barton.de Git - netatalk.git/blob - libatalk/adouble/ad_flush.c
Merge master
[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
41 #include "ad_lock.h"
42
43 static const uint32_t set_eid[] = {
44     0,1,2,3,4,5,6,7,8,
45     9,10,11,12,13,14,15,
46     AD_DEV, AD_INO, AD_SYN, AD_ID
47 };
48
49 #define EID_DISK(a) (set_eid[a])
50
51 /*
52  * Rebuild any header information that might have changed.
53  */
54 int  ad_rebuild_adouble_header(struct adouble *ad)
55 {
56     uint32_t       eid;
57     uint32_t       temp;
58     uint16_t       nent;
59     char        *buf, *nentp;
60     int             len;
61
62     buf = ad->ad_data;
63
64     temp = htonl( ad->ad_magic );
65     memcpy(buf, &temp, sizeof( temp ));
66     buf += sizeof( temp );
67
68     temp = htonl( ad->ad_version );
69     memcpy(buf, &temp, sizeof( temp ));
70     buf += sizeof( temp );
71
72     buf += sizeof( ad->ad_filler );
73
74     nentp = buf;
75     buf += sizeof( nent );
76     for ( eid = 0, nent = 0; eid < ADEID_MAX; eid++ ) {
77         if ( ad->ad_eid[ eid ].ade_off == 0 ) {
78             continue;
79         }
80         temp = htonl( EID_DISK(eid) );
81         memcpy(buf, &temp, sizeof( temp ));
82         buf += sizeof( temp );
83
84         temp = htonl( ad->ad_eid[ eid ].ade_off );
85         memcpy(buf, &temp, sizeof( temp ));
86         buf += sizeof( temp );
87
88         temp = htonl( ad->ad_eid[ eid ].ade_len );
89         memcpy(buf, &temp, sizeof( temp ));
90         buf += sizeof( temp );
91         nent++;
92     }
93     nent = htons( nent );
94     memcpy(nentp, &nent, sizeof( nent ));
95
96     switch (ad->ad_flags) {
97     case AD_VERSION2:
98         len = ad_getentryoff(ad, ADEID_RFORK);
99         break;
100     case AD_VERSION_EA:
101         len = AD_DATASZ_EA;
102         break;
103     default:
104         LOG(log_error, logtype_afpd, "Unexpected adouble version");
105         len = 0;
106         break;
107     }
108
109     return len;
110 }
111
112 /* -------------------
113  * XXX copy only header with same size or comment
114  * doesn't work well for adouble with different version.
115  *
116  */
117 int ad_copy_header(struct adouble *add, struct adouble *ads)
118 {
119     uint32_t       eid;
120     uint32_t       len;
121
122     for ( eid = 0; eid < ADEID_MAX; eid++ ) {
123         if ( ads->ad_eid[ eid ].ade_off == 0 ) {
124             continue;
125         }
126
127         if ( add->ad_eid[ eid ].ade_off == 0 ) {
128             continue;
129         }
130
131         len = ads->ad_eid[ eid ].ade_len;
132         if (!len) {
133             continue;
134         }
135
136         if (eid != ADEID_COMMENT && add->ad_eid[ eid ].ade_len != len ) {
137             continue;
138         }
139
140         ad_setentrylen( add, eid, len );
141         memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len );
142     }
143     add->ad_rlen = ads->ad_rlen;
144     return 0;
145 }
146
147 int ad_flush(struct adouble *ad)
148 {
149     int len;
150     struct ad_fd *adf;
151
152     switch (ad->ad_flags) {
153     case AD_VERSION2:
154         adf = ad->ad_mdp;
155         break;
156     case AD_VERSION_EA:
157         adf = &ad->ad_data_fork;
158         break;
159     default:
160         LOG(log_error, logtype_afpd, "ad_flush: unexpected adouble version");
161         return -1;
162     }
163
164     if ((adf->adf_flags & O_RDWR)) {
165         if (ad_getentryoff(ad, ADEID_RFORK)) {
166             if (ad->ad_rlen > 0xffffffff)
167                 ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
168             else
169                 ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
170         }
171         len = ad->ad_ops->ad_rebuild_header(ad);
172
173         switch (ad->ad_flags) {
174         case AD_VERSION2:
175             if (adf_pwrite(ad->ad_mdp, ad->ad_data, len, 0) != len) {
176                 if (errno == 0)
177                     errno = EIO;
178                 return( -1 );
179             }
180             break;
181         case AD_VERSION_EA:
182             if (sys_fsetxattr(ad_data_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) != 0) {
183                 LOG(log_error, logtype_afpd, "ad_flush: sys_fsetxattr error: %s",
184                     strerror(errno));
185                 return -1;
186             }
187             break;
188         default:
189             LOG(log_error, logtype_afpd, "ad_flush: unexpected adouble version");
190             return -1;
191         }
192     }
193
194     return( 0 );
195 }
196
197 /*!
198  * Close a struct adouble freeing all resources
199  */
200 int ad_close(struct adouble *ad, int adflags)
201 {
202     int err = 0;
203
204     if (ad == NULL)
205         return err;
206
207     LOG(log_debug, logtype_default, "ad_close(%s)", adflags2logstr(adflags));
208
209     if ((adflags & ADFLAGS_DF)
210         && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == -2) /* -2 means symlink */
211         && --ad->ad_data_fork.adf_refcount == 0) {
212         if (ad->ad_data_fork.adf_syml != NULL) {
213             free(ad->ad_data_fork.adf_syml);
214             ad->ad_data_fork.adf_syml = 0;
215         } else {
216             if ( close( ad_data_fileno(ad) ) < 0 )
217                 err = -1;
218         }
219         ad_data_fileno(ad) = -1;
220         adf_lock_free(&ad->ad_data_fork);
221     }
222
223     if ((adflags & ADFLAGS_HF)) {
224         switch (ad->ad_flags) {
225         case AD_VERSION2:
226             if ((ad_meta_fileno(ad) != -1) && !(--ad->ad_mdp->adf_refcount)) {
227                 if (close( ad_meta_fileno(ad) ) < 0)
228                     err = -1;
229                 ad_meta_fileno(ad) = -1;
230                 adf_lock_free(ad->ad_mdp);
231             }
232             break;
233
234         case AD_VERSION_EA:
235             if ((ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == -2) /* -2 means symlink */ 
236                 && !(--ad->ad_data_fork.adf_refcount)) {
237                 if (close( ad_data_fileno(ad) ) < 0)
238                     err = -1;
239                 ad_data_fileno(ad) = -1;
240                 adf_lock_free(&ad->ad_data_fork);
241             }
242             break;
243
244         default:
245             LOG(log_error, logtype_default, "ad_close: unknown AD version");
246             errno = EIO;
247             return -1;
248         }
249     }
250
251     return err;
252 }