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