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