]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/ofork.c
of_findname: remove vol and dir
[netatalk.git] / etc / afpd / ofork.c
1 /*
2  * $Id: ofork.c,v 1.18 2002-09-05 14:52:07 didg Exp $
3  *
4  * Copyright (c) 1996 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h> /* works around a bug */
16 #include <sys/param.h>
17 #include <atalk/logger.h>
18 #include <errno.h>
19
20 #include <atalk/adouble.h>
21
22 #include "globals.h"
23 #include "volume.h"
24 #include "directory.h"
25 #include "fork.h"
26
27 /* we need to have a hashed list of oforks (by dev inode). just hash
28  * by first letter. */
29 #define OFORK_HASHSIZE  64
30 static struct ofork     *ofork_table[OFORK_HASHSIZE];
31
32 static struct ofork     **oforks = NULL;
33 static int              nforks = 0;
34 static u_short          lastrefnum = 0;
35
36
37 /* OR some of each character for the hash*/
38 static __inline__ unsigned long hashfn(const struct file_key *key)
39 {
40     unsigned long i = 0;
41 #if 0
42     while (*name) {
43         i = ((i << 4) | (8*sizeof(i) - 4)) ^ *name++;
44     }
45 #endif    
46     return key->inode & (OFORK_HASHSIZE - 1);
47 }
48
49 static __inline__ void of_hash(struct ofork *of)
50 {
51     struct ofork **table;
52
53     table = &ofork_table[hashfn(&of->key)];
54     if ((of->next = *table) != NULL)
55         (*table)->prevp = &of->next;
56     *table = of;
57     of->prevp = table;
58 }
59
60 static __inline__ void of_unhash(struct ofork *of)
61 {
62     if (of->prevp) {
63         if (of->next)
64             of->next->prevp = of->prevp;
65         *(of->prevp) = of->next;
66     }
67 }
68
69 void of_pforkdesc( f )
70 FILE    *f;
71 {
72     int ofrefnum;
73
74     if (!oforks)
75         return;
76
77     for ( ofrefnum = 0; ofrefnum < nforks; ofrefnum++ ) {
78         if ( oforks[ ofrefnum ] != NULL ) {
79             fprintf( f, "%hu <%s>\n", ofrefnum, oforks[ ofrefnum ]->of_name);
80         }
81     }
82 }
83
84 int of_flush(const struct vol *vol)
85 {
86     int refnum;
87
88     if (!oforks)
89         return 0;
90
91     for ( refnum = 0; refnum < nforks; refnum++ ) {
92         if (oforks[ refnum ] != NULL && (oforks[refnum]->of_vol == vol) &&
93                 flushfork( oforks[ refnum ] ) < 0 ) {
94             LOG(log_error, logtype_afpd, "of_flush: %s", strerror(errno) );
95         }
96     }
97     return( 0 );
98 }
99
100 int of_rename(vol, s_of, olddir, oldpath, newdir, newpath)
101 const struct vol *vol;
102 struct ofork *s_of;
103 struct dir *olddir, *newdir;
104 const char *oldpath, *newpath;
105 {
106     struct ofork *of, *next, *d_ofork;
107
108     if (!s_of)
109         return AFP_OK;
110         
111     next = ofork_table[hashfn(&s_of->key)];
112     while ((of = next)) {
113         next = next->next; /* so we can unhash and still be all right. */
114
115         if (vol == of->of_vol && olddir == of->of_dir &&
116                  s_of->key.dev == of->key.dev && 
117                  s_of->key.inode == of->key.inode ) {
118             of_unhash(of);
119             strncpy( of->of_name, newpath, of->of_namelen);
120             of->of_d_prev->of_d_next = of->of_d_next;
121             of->of_d_next->of_d_prev = of->of_d_prev;
122             if (of->of_dir->d_ofork == of) {
123                 of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
124             }       
125             of->of_dir = newdir;
126             if (!(d_ofork = newdir->d_ofork)) {
127                 newdir->d_ofork = of;
128                 of->of_d_next = of->of_d_prev = of;
129             } else {
130                 of->of_d_next = d_ofork;
131                 of->of_d_prev = d_ofork->of_d_prev;
132                 of->of_d_prev->of_d_next = of;
133                 d_ofork->of_d_prev = of;
134             }
135             of_hash(of);
136         }
137     }
138
139     return AFP_OK;
140 }
141
142 #define min(a,b)        ((a)<(b)?(a):(b))
143
144 struct ofork *
145             of_alloc(vol, dir, path, ofrefnum, eid, ad, st)
146 struct vol      *vol;
147 struct dir      *dir;
148 char            *path;
149 u_int16_t       *ofrefnum;
150 const int       eid;
151 struct adouble  *ad;
152 struct stat     *st;
153 {
154     struct ofork        *of, *d_ofork;
155     u_int16_t           refnum, of_refnum;
156
157     int                 i;
158
159     if (!oforks) {
160         nforks = (getdtablesize() - 10) / 2;
161         /* protect against insane ulimit -n */
162         nforks = min(nforks, 0xffff);
163         oforks = (struct ofork **) calloc(nforks, sizeof(struct ofork *));
164         if (!oforks)
165             return NULL;
166     }
167
168     for ( refnum = ++lastrefnum, i = 0; i < nforks; i++, refnum++ ) {
169         /* cf AFP3.0.pdf, File fork page 40 */
170         if (!refnum)
171             refnum++;
172         if ( oforks[ refnum % nforks ] == NULL ) {
173             break;
174         }
175     }
176     /* grr, Apple and their 'uniquely identifies'
177           the next line is a protection against 
178           of_alloc()
179              refnum % nforks = 3 
180              lastrefnum = 3
181              oforks[3] != NULL 
182              refnum = 4
183              oforks[4] == NULL
184              return 4
185          
186           close(oforks[4])
187       
188           of_alloc()
189              refnum % nforks = 4
190              ...
191              return 4
192          same if lastrefnum++ rather than ++lastrefnum. 
193     */
194     lastrefnum = refnum;
195     if ( i == nforks ) {
196         LOG(log_error, logtype_afpd, "of_alloc: maximum number of forks exceeded.");
197         return( NULL );
198     }
199
200     of_refnum = refnum % nforks;
201     if (( oforks[ of_refnum ] =
202                 (struct ofork *)malloc( sizeof( struct ofork ))) == NULL ) {
203         LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
204         return NULL;
205     }
206     of = oforks[of_refnum];
207
208     /* see if we need to allocate space for the adouble struct */
209     if (!ad) {
210         ad = malloc( sizeof( struct adouble ) );
211         if (!ad) {
212             LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
213             return NULL;
214         }
215
216         /* initialize to zero. This is important to ensure that
217            ad_open really does reinitialize the structure. */
218         memset( ad, 0, sizeof( struct adouble ) );
219     } else {
220         /* Increase the refcount on this struct adouble. This is
221            decremented again in oforc_dealloc. */
222         ad->ad_refcount++;
223     }
224
225     of->of_ad = ad;
226
227     of->of_vol = vol;
228     of->of_dir = dir;
229
230     if (!(d_ofork = dir->d_ofork)) {
231         dir->d_ofork = of;
232         of->of_d_next = of->of_d_prev = of;
233     } else {
234         of->of_d_next = d_ofork;
235         of->of_d_prev = d_ofork->of_d_prev;
236         d_ofork->of_d_prev->of_d_next = of;
237         d_ofork->of_d_prev = of;
238     }
239
240     /* here's the deal: we allocate enough for the standard mac file length.
241      * in the future, we'll reallocate in fairly large jumps in case
242      * of long unicode names */
243     if (( of->of_name =(char *)malloc(255 + 1)) == NULL ) {
244         LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
245         if (!ad)
246             free(of->of_ad);
247         free(of);
248         oforks[ of_refnum ] = NULL;
249         return NULL;
250     }
251     strncpy( of->of_name, path, of->of_namelen = 255 + 1);
252     *ofrefnum = refnum;
253     of->of_refnum = refnum;
254     of->key.dev = st->st_dev;
255     of->key.inode = st->st_ino;
256     if (eid == ADEID_DFORK)
257         of->of_flags = AFPFORK_DATA;
258     else
259         of->of_flags = AFPFORK_RSRC;
260
261     of_hash(of);
262     return( of );
263 }
264
265 struct ofork *of_find(const u_int16_t ofrefnum )
266 {
267     if (!oforks || !nforks)
268         return NULL;
269
270     return( oforks[ ofrefnum % nforks ] );
271 }
272
273 /* --------------------------
274 */
275 struct ofork *
276             of_findname(const char *name, struct stat *st)
277 {
278     struct ofork *of;
279     struct file_key key;
280     struct stat buffer;
281     char   *p;
282     
283     if (st == NULL) {
284         st = &buffer;
285         if (stat(name, st) < 0)
286             return NULL;
287     }
288     key.dev = st->st_dev;
289     key.inode = st->st_ino;
290
291     for (of = ofork_table[hashfn(&key)]; of; of = of->next) {
292         if (key.dev == of->key.dev && key.inode == of->key.inode ) {
293             return of;
294         }
295     }
296
297     return NULL;
298 }
299
300 void of_dealloc( of )
301 struct ofork    *of;
302 {
303     if (!oforks)
304         return;
305
306     of_unhash(of);
307
308     /* detach ofork */
309     of->of_d_prev->of_d_next = of->of_d_next;
310     of->of_d_next->of_d_prev = of->of_d_prev;
311     if (of->of_dir->d_ofork == of) {
312         of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
313     }
314
315     oforks[ of->of_refnum % nforks ] = NULL;
316     free( of->of_name );
317
318     /* decrease refcount */
319     of->of_ad->ad_refcount--;
320
321     if ( of->of_ad->ad_refcount <= 0) {
322         free( of->of_ad);
323     } else {/* someone's still using it. just free this user's locks */
324         ad_unlock(of->of_ad, of->of_refnum);
325     }
326
327     free( of );
328 }