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