]> arthur.barton.de Git - netatalk.git/blob - libatalk/adouble/ad_flush.c
Fix for memory leaks with symlinks, fixes #3074077 and #3074078
[netatalk.git] / libatalk / adouble / ad_flush.c
1 /*
2  * Copyright (c) 1990,1991 Regents of The University of Michigan.
3  * All Rights Reserved.
4  *
5  * Permission to use, copy, modify, and distribute this software and
6  * its documentation for any purpose and without fee is hereby granted,
7  * provided that the above copyright notice appears in all copies and
8  * that both that copyright notice and this permission notice appear
9  * in supporting documentation, and that the name of The University
10  * of Michigan not be used in advertising or publicity pertaining to
11  * distribution of the software without specific, written prior
12  * permission. This software is supplied as is without expressed or
13  * implied warranties of any kind.
14  *
15  *  Research Systems Unix Group
16  *  The University of Michigan
17  *  c/o Mike Clark
18  *  535 W. William Street
19  *  Ann Arbor, Michigan
20  *  +1-313-763-0525
21  *  netatalk@itd.umich.edu
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif /* HAVE_CONFIG_H */
27
28 #include <string.h>
29 #include <atalk/adouble.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34
35 #include "ad_private.h"
36 #if AD_VERSION == AD_VERSION1
37
38 #define EID_DISK(a) (a)
39
40 #else
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 #endif
50
51 /* rebuild the adouble header
52  * XXX should be in a separate file ?
53  */
54 int  ad_rebuild_adouble_header(struct adouble *ad)
55 {
56     u_int32_t       eid;
57     u_int32_t       temp;
58
59     u_int16_t       nent;
60     char        *buf, *nentp;
61
62     /*
63      * Rebuild any header information that might have changed.
64      */
65     buf = ad->ad_data;
66
67     temp = htonl( ad->ad_magic );
68     memcpy(buf, &temp, sizeof( temp ));
69     buf += sizeof( temp );
70
71     temp = htonl( ad->ad_version );
72     memcpy(buf, &temp, sizeof( temp ));
73     buf += sizeof( temp );
74
75     memcpy(buf, ad->ad_filler, sizeof( ad->ad_filler ));
76     buf += sizeof( ad->ad_filler );
77
78     nentp = buf;
79     buf += sizeof( nent );
80     for ( eid = 0, nent = 0; eid < ADEID_MAX; eid++ ) {
81         if ( ad->ad_eid[ eid ].ade_off == 0 ) {
82             continue;
83         }
84         temp = htonl( EID_DISK(eid) );
85         memcpy(buf, &temp, sizeof( temp ));
86         buf += sizeof( temp );
87
88         temp = htonl( ad->ad_eid[ eid ].ade_off );
89         memcpy(buf, &temp, sizeof( temp ));
90         buf += sizeof( temp );
91
92         temp = htonl( ad->ad_eid[ eid ].ade_len );
93         memcpy(buf, &temp, sizeof( temp ));
94         buf += sizeof( temp );
95         nent++;
96     }
97     nent = htons( nent );
98     memcpy(nentp, &nent, sizeof( nent ));
99     return ad_getentryoff(ad, ADEID_RFORK);
100 }
101
102 /* -------------------
103  * XXX copy only header with same size or comment
104  * doesn't work well for adouble with different version.
105  *
106  */
107 int ad_copy_header(struct adouble *add, struct adouble *ads)
108 {
109     u_int32_t       eid;
110     u_int32_t       len;
111
112     for ( eid = 0; eid < ADEID_MAX; eid++ ) {
113         if ( ads->ad_eid[ eid ].ade_off == 0 ) {
114             continue;
115         }
116
117         if ( add->ad_eid[ eid ].ade_off == 0 ) {
118             continue;
119         }
120
121         len = ads->ad_eid[ eid ].ade_len;
122         if (!len) {
123             continue;
124         }
125
126         if (eid != ADEID_COMMENT && add->ad_eid[ eid ].ade_len != len ) {
127             continue;
128         }
129
130         ad_setentrylen( add, eid, len );
131         memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len );
132     }
133     add->ad_rlen = ads->ad_rlen;
134     return 0;
135 }
136
137 /* ------------------- */
138 int  ad_rebuild_sfm_header(struct adouble *ad)
139 {
140     u_int32_t       temp;
141
142     u_int16_t       attr;
143     char        *buf;
144
145     /*
146      * Rebuild any header information that might have changed.
147      */
148     buf = ad->ad_data;
149     /* FIXME */
150 /*    temp = htonl( ad->ad_magic ); */
151     temp = ad->ad_magic;
152     memcpy(buf, &temp, sizeof( temp ));
153
154 /*    temp = htonl( ad->ad_version ); */
155     temp = ad->ad_version;
156     memcpy(buf +4, &temp, sizeof( temp ));
157
158     /* need to save attrib */
159     if (!ad_getattr(ad, &attr)) {
160         attr &= ~htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN);
161
162         memcpy(buf +48 +4, &attr, sizeof(attr));
163
164     }
165     return AD_SFM_LEN;
166 }
167
168
169 int ad_flush( struct adouble *ad)
170 {
171     int len;
172
173     if (( ad->ad_md->adf_flags & O_RDWR )) {
174         /* sync our header */
175         if (ad->ad_rlen > 0xffffffff) {
176             ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
177         }
178         else {
179             ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
180         }
181         len = ad->ad_ops->ad_rebuild_header(ad);
182
183         if (adf_pwrite(ad->ad_md, ad->ad_data, len, 0) != len) {
184             if ( errno == 0 ) {
185                 errno = EIO;
186             }
187             return( -1 );
188         }
189     }
190
191     return( 0 );
192 }
193
194 /* use refcounts so that we don't have to re-establish fcntl locks. */
195 int ad_close( struct adouble *ad, int adflags)
196 {
197     int         err = 0;
198
199     if ((adflags & ADFLAGS_DF)
200         && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == -2) /* -2 means symlink */
201         && --ad->ad_data_fork.adf_refcount == 0) {
202         if (ad->ad_data_fork.adf_syml != NULL) {
203             free(ad->ad_data_fork.adf_syml);
204             ad->ad_data_fork.adf_syml = 0;
205         } else {
206             if ( close( ad_data_fileno(ad) ) < 0 )
207                 err = -1;
208         }
209         ad_data_fileno(ad) = -1;
210         adf_lock_free(&ad->ad_data_fork);
211     }
212
213     if (!( adflags & ADFLAGS_HF )) {
214         return err;
215     }
216
217     /* meta /resource fork */
218
219     if ( ad_meta_fileno(ad) != -1 && !(--ad->ad_md->adf_refcount)) {
220         if ( close( ad_meta_fileno(ad) ) < 0 ) {
221             err = -1;
222         }
223         ad_meta_fileno(ad) = -1;
224         adf_lock_free(ad->ad_md);
225     }
226
227     if (ad->ad_flags != AD_VERSION1_SFM) {
228         return err;
229     }
230
231     if ((adflags & ADFLAGS_DIR)) {
232         return err;
233     }
234
235     if ( ad_reso_fileno(ad) != -1 && !(--ad->ad_resource_fork.adf_refcount)) {
236         if ( close( ad_reso_fileno(ad) ) < 0 ) {
237             err = -1;
238         }
239         ad_reso_fileno(ad) = -1;
240         adf_lock_free(&ad->ad_resource_fork);
241     }
242
243     return err;
244 }