]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/ofork.c
remove gcc warnings and cleanup inline mess
[netatalk.git] / etc / afpd / ofork.c
1 /*
2  * $Id: ofork.c,v 1.20.6.6.2.7 2008-11-25 15:16:33 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 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 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 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, of_name(oforks[ ofrefnum ]));
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     int done = 0;
113
114     if (!s_of)
115         return AFP_OK;
116         
117     next = ofork_table[hashfn(&s_of->key)];
118     while ((of = next)) {
119         next = next->next; /* so we can unhash and still be all right. */
120
121         if (vol == of->of_vol && olddir == of->of_dir &&
122                  s_of->key.dev == of->key.dev && 
123                  s_of->key.inode == of->key.inode ) {
124             if (!done) {
125                 strlcpy( of_name(of), newpath, of->of_ad->ad_m_namelen);
126                 done = 1;
127             }
128             if (newdir != olddir) {
129                 of->of_d_prev->of_d_next = of->of_d_next;
130                 of->of_d_next->of_d_prev = of->of_d_prev;
131                 if (of->of_dir->d_ofork == of) {
132                     of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
133                 }           
134                 of->of_dir = newdir;
135                 if (!(d_ofork = newdir->d_ofork)) {
136                     newdir->d_ofork = of;
137                     of->of_d_next = of->of_d_prev = of;
138                 } else {
139                     of->of_d_next = d_ofork;
140                     of->of_d_prev = d_ofork->of_d_prev;
141                     of->of_d_prev->of_d_next = of;
142                     d_ofork->of_d_prev = of;
143                 }
144             }
145         }
146     }
147
148     return AFP_OK;
149 }
150
151 #define min(a,b)        ((a)<(b)?(a):(b))
152
153 struct ofork *
154             of_alloc(vol, dir, path, ofrefnum, eid, ad, st)
155 struct vol      *vol;
156 struct dir      *dir;
157 char            *path;
158 u_int16_t       *ofrefnum;
159 const int       eid;
160 struct adouble  *ad;
161 struct stat     *st;
162 {
163     struct ofork        *of, *d_ofork;
164     u_int16_t           refnum, of_refnum;
165
166     int                 i;
167
168     if (!oforks) {
169         nforks = getdtablesize() - 10;
170         /* protect against insane ulimit -n */
171         nforks = min(nforks, 0xffff);
172         oforks = (struct ofork **) calloc(nforks, sizeof(struct ofork *));
173         if (!oforks)
174             return NULL;
175     }
176
177     for ( refnum = ++lastrefnum, i = 0; i < nforks; i++, refnum++ ) {
178         /* cf AFP3.0.pdf, File fork page 40 */
179         if (!refnum)
180             refnum++;
181         if ( oforks[ refnum % nforks ] == NULL ) {
182             break;
183         }
184     }
185     /* grr, Apple and their 'uniquely identifies'
186           the next line is a protection against 
187           of_alloc()
188              refnum % nforks = 3 
189              lastrefnum = 3
190              oforks[3] != NULL 
191              refnum = 4
192              oforks[4] == NULL
193              return 4
194          
195           close(oforks[4])
196       
197           of_alloc()
198              refnum % nforks = 4
199              ...
200              return 4
201          same if lastrefnum++ rather than ++lastrefnum. 
202     */
203     lastrefnum = refnum;
204     if ( i == nforks ) {
205         LOG(log_error, logtype_afpd, "of_alloc: maximum number of forks exceeded.");
206         return( NULL );
207     }
208
209     of_refnum = refnum % nforks;
210     if (( oforks[ of_refnum ] =
211                 (struct ofork *)malloc( sizeof( struct ofork ))) == NULL ) {
212         LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
213         return NULL;
214     }
215     of = oforks[of_refnum];
216
217     /* see if we need to allocate space for the adouble struct */
218     if (!ad) {
219         ad = malloc( sizeof( struct adouble ) );
220         if (!ad) {
221             LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
222             free(of);
223             oforks[ of_refnum ] = NULL;
224             return NULL;
225         }
226
227         /* initialize to zero. This is important to ensure that
228            ad_open really does reinitialize the structure. */
229         ad_init(ad, vol->v_adouble, vol->v_ad_options);
230
231         ad->ad_m_namelen = 255 +1;
232         /* here's the deal: we allocate enough for the standard mac file length.
233          * in the future, we'll reallocate in fairly large jumps in case
234          * of long unicode names */
235         if (( ad->ad_m_name =(char *)malloc( ad->ad_m_namelen )) == NULL ) {
236             LOG(log_error, logtype_afpd, "of_alloc: malloc: %s", strerror(errno) );
237             free(ad);
238             free(of);
239             oforks[ of_refnum ] = NULL;
240             return NULL;
241         }
242         strlcpy( ad->ad_m_name, path, ad->ad_m_namelen);
243     } else {
244         /* Increase the refcount on this struct adouble. This is
245            decremented again in oforc_dealloc. */
246         ad->ad_refcount++;
247     }
248
249     of->of_ad = ad;
250     of->of_vol = vol;
251     of->of_dir = dir;
252
253     if (!(d_ofork = dir->d_ofork)) {
254         dir->d_ofork = of;
255         of->of_d_next = of->of_d_prev = of;
256     } else {
257         of->of_d_next = d_ofork;
258         of->of_d_prev = d_ofork->of_d_prev;
259         d_ofork->of_d_prev->of_d_next = of;
260         d_ofork->of_d_prev = of;
261     }
262
263     *ofrefnum = refnum;
264     of->of_refnum = refnum;
265     of->key.dev = st->st_dev;
266     of->key.inode = st->st_ino;
267     if (eid == ADEID_DFORK)
268         of->of_flags = AFPFORK_DATA;
269     else
270         of->of_flags = AFPFORK_RSRC;
271
272     of_hash(of);
273     return( of );
274 }
275
276 struct ofork *of_find(const u_int16_t ofrefnum )
277 {
278     if (!oforks || !nforks)
279         return NULL;
280
281     return( oforks[ ofrefnum % nforks ] );
282 }
283
284 /* -------------------------- */
285 int of_stat  (struct path *path)
286 {
287 int ret;
288     path->st_errno = 0;
289     path->st_valid = 1;
290     if ((ret = stat(path->u_name, &path->st)) < 0)
291         path->st_errno = errno;
292    return ret;
293 }
294
295 /* -------------------------- */
296 int of_statdir  (const struct vol *vol, struct path *path)
297 {
298 static char pathname[ MAXPATHLEN + 1];
299 int ret;
300
301     if (*path->m_name) {
302         /* not curdir */
303         return of_stat (path);
304     }
305     path->st_errno = 0;
306     path->st_valid = 1;
307     /* FIXME, what about: we don't have r-x perm anymore ? */
308     strcpy(pathname, "../");
309     strlcat(pathname, path->d_dir->d_u_name, MAXPATHLEN);
310
311     if (!(ret = stat(pathname, &path->st)))
312         return 0;
313         
314     path->st_errno = errno;
315     /* hmm, can't stat curdir anymore */
316     if (errno == EACCES && curdir->d_parent ) {
317        if (movecwd(vol, curdir->d_parent)) 
318            return -1;
319        path->st_errno = 0;
320        if ((ret = stat(path->d_dir->d_u_name, &path->st)) < 0) 
321            path->st_errno = errno;
322     }
323     return ret;
324 }
325
326 /* -------------------------- */
327 struct ofork *
328             of_findname(struct path *path)
329 {
330     struct ofork *of;
331     struct file_key key;
332     
333     if (!path->st_valid) {
334        of_stat(path);
335     }
336         
337     if (path->st_errno)
338         return NULL;
339
340     key.dev = path->st.st_dev;
341     key.inode = path->st.st_ino;
342
343     for (of = ofork_table[hashfn(&key)]; of; of = of->next) {
344         if (key.dev == of->key.dev && key.inode == of->key.inode ) {
345             return of;
346         }
347     }
348
349     return NULL;
350 }
351
352 void of_dealloc( of )
353 struct ofork    *of;
354 {
355     if (!oforks)
356         return;
357
358     of_unhash(of);
359
360     /* detach ofork */
361     of->of_d_prev->of_d_next = of->of_d_next;
362     of->of_d_next->of_d_prev = of->of_d_prev;
363     if (of->of_dir->d_ofork == of) {
364         of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
365     }
366
367     oforks[ of->of_refnum % nforks ] = NULL;
368
369     /* decrease refcount */
370     of->of_ad->ad_refcount--;
371
372     if ( of->of_ad->ad_refcount <= 0) {
373         free( of->of_ad->ad_m_name );
374         free( of->of_ad);
375     } else {/* someone's still using it. just free this user's locks */
376         ad_unlock(of->of_ad, of->of_refnum);
377     }
378
379     free( of );
380 }
381
382 /* ----------------------
383
384 */
385 struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *ad)
386 {
387     struct ofork        *of;
388     struct adouble      *adp;
389
390     if ((of = of_findname(path))) {
391         adp = of->of_ad;
392     } else {
393         ad_init(ad, vol->v_adouble, vol->v_ad_options);
394         adp = ad;
395     }
396     return adp;
397 }
398