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