]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/ofork.c
Remove a lot of warning, from cvs HEAD
[netatalk.git] / etc / afpd / ofork.c
1 /*
2  * $Id: ofork.c,v 1.20.6.6.2.4 2005-09-27 10:40:41 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 _U_, *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     /* here's the deal: we allocate enough for the standard mac file length.
214      * in the future, we'll reallocate in fairly large jumps in case
215      * of long unicode names */
216     of->of_namelen = 255 +1;
217     if (( of->of_name =(char *)malloc( of->of_namelen )) == NULL ) {
218         LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
219         free(of);
220         oforks[ of_refnum ] = NULL;
221         return NULL;
222     }
223
224     /* see if we need to allocate space for the adouble struct */
225     if (!ad) {
226         ad = malloc( sizeof( struct adouble ) );
227         if (!ad) {
228             LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
229             free(of->of_name);
230             free(of);
231             oforks[ of_refnum ] = NULL;
232             return NULL;
233         }
234
235         /* initialize to zero. This is important to ensure that
236            ad_open really does reinitialize the structure. */
237         ad_init(ad, vol->v_adouble, vol->v_ad_options);
238     } else {
239         /* Increase the refcount on this struct adouble. This is
240            decremented again in oforc_dealloc. */
241         ad->ad_refcount++;
242     }
243
244     of->of_ad = ad;
245     of->of_vol = vol;
246     of->of_dir = dir;
247
248     if (!(d_ofork = dir->d_ofork)) {
249         dir->d_ofork = of;
250         of->of_d_next = of->of_d_prev = of;
251     } else {
252         of->of_d_next = d_ofork;
253         of->of_d_prev = d_ofork->of_d_prev;
254         d_ofork->of_d_prev->of_d_next = of;
255         d_ofork->of_d_prev = of;
256     }
257
258     strlcpy( of->of_name, path, of->of_namelen);
259     *ofrefnum = refnum;
260     of->of_refnum = refnum;
261     of->key.dev = st->st_dev;
262     of->key.inode = st->st_ino;
263     if (eid == ADEID_DFORK)
264         of->of_flags = AFPFORK_DATA;
265     else
266         of->of_flags = AFPFORK_RSRC;
267
268     of_hash(of);
269     return( of );
270 }
271
272 struct ofork *of_find(const u_int16_t ofrefnum )
273 {
274     if (!oforks || !nforks)
275         return NULL;
276
277     return( oforks[ ofrefnum % nforks ] );
278 }
279
280 /* -------------------------- */
281 int of_stat  (struct path *path)
282 {
283 int ret;
284     path->st_errno = 0;
285     path->st_valid = 1;
286     if ((ret = stat(path->u_name, &path->st)) < 0)
287         path->st_errno = errno;
288    return ret;
289 }
290
291 /* -------------------------- */
292 int of_statdir  (const struct vol *vol, struct path *path)
293 {
294 static char pathname[ MAXPATHLEN + 1];
295 int ret;
296
297     if (*path->m_name) {
298         /* not curdir */
299         return of_stat (path);
300     }
301     path->st_errno = 0;
302     path->st_valid = 1;
303     /* FIXME, what about: we don't have r-x perm anymore ? */
304     strcpy(pathname, "../");
305     strlcat(pathname, path->d_dir->d_u_name, MAXPATHLEN);
306
307     if (!(ret = stat(pathname, &path->st)))
308         return 0;
309         
310     path->st_errno = errno;
311     /* hmm, can't stat curdir anymore */
312     if (errno == EACCES && curdir->d_parent ) {
313        if (movecwd(vol, curdir->d_parent)) 
314            return -1;
315        path->st_errno = 0;
316        if ((ret = stat(path->d_dir->d_u_name, &path->st)) < 0) 
317            path->st_errno = errno;
318     }
319     return ret;
320 }
321
322 /* -------------------------- */
323 struct ofork *
324             of_findname(struct path *path)
325 {
326     struct ofork *of;
327     struct file_key key;
328     
329     if (!path->st_valid) {
330        of_stat(path);
331     }
332         
333     if (path->st_errno)
334         return NULL;
335
336     key.dev = path->st.st_dev;
337     key.inode = path->st.st_ino;
338
339     for (of = ofork_table[hashfn(&key)]; of; of = of->next) {
340         if (key.dev == of->key.dev && key.inode == of->key.inode ) {
341             return of;
342         }
343     }
344
345     return NULL;
346 }
347
348 void of_dealloc( of )
349 struct ofork    *of;
350 {
351     if (!oforks)
352         return;
353
354     of_unhash(of);
355
356     /* detach ofork */
357     of->of_d_prev->of_d_next = of->of_d_next;
358     of->of_d_next->of_d_prev = of->of_d_prev;
359     if (of->of_dir->d_ofork == of) {
360         of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
361     }
362
363     oforks[ of->of_refnum % nforks ] = NULL;
364     free( of->of_name );
365
366     /* decrease refcount */
367     of->of_ad->ad_refcount--;
368
369     if ( of->of_ad->ad_refcount <= 0) {
370         free( of->of_ad);
371     } else {/* someone's still using it. just free this user's locks */
372         ad_unlock(of->of_ad, of->of_refnum);
373     }
374
375     free( of );
376 }
377
378 /* ----------------------
379
380 */
381 struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *ad)
382 {
383     struct ofork        *of;
384     struct adouble      *adp;
385
386     if ((of = of_findname(path))) {
387         adp = of->of_ad;
388     } else {
389         ad_init(ad, vol->v_adouble, vol->v_ad_options);
390         adp = ad;
391     }
392     return adp;
393 }
394