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