]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/ofork.c
Remove excessive logging.
[netatalk.git] / etc / afpd / ofork.c
1 /*
2  * $Id: ofork.c,v 1.30.4.2 2010-02-04 14:34:31 franklahm 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 <errno.h>
21
22 #include <atalk/logger.h>
23 #include <atalk/util.h>
24 #include <atalk/bstrlib.h>
25 #include <atalk/bstradd.h>
26
27 #include "globals.h"
28 #include "volume.h"
29 #include "directory.h"
30 #include "fork.h"
31
32 /* we need to have a hashed list of oforks (by dev inode). just hash
33  * by first letter. */
34 #define OFORK_HASHSIZE  64
35 static struct ofork     *ofork_table[OFORK_HASHSIZE];
36
37 static struct ofork     **oforks = NULL;
38 static int              nforks = 0;
39 static u_short          lastrefnum = 0;
40
41
42 /* OR some of each character for the hash*/
43 static unsigned long hashfn(const struct file_key *key)
44 {
45 #if 0
46     unsigned long i = 0;
47     while (*name) {
48         i = ((i << 4) | (8*sizeof(i) - 4)) ^ *name++;
49     }
50 #endif    
51     return key->inode & (OFORK_HASHSIZE - 1);
52 }
53
54 static void of_hash(struct ofork *of)
55 {
56     struct ofork **table;
57
58     table = &ofork_table[hashfn(&of->key)];
59     if ((of->next = *table) != NULL)
60         (*table)->prevp = &of->next;
61     *table = of;
62     of->prevp = table;
63 }
64
65 static void of_unhash(struct ofork *of)
66 {
67     if (of->prevp) {
68         if (of->next)
69             of->next->prevp = of->prevp;
70         *(of->prevp) = of->next;
71     }
72 }
73
74 #ifdef DEBUG1
75 void of_pforkdesc( FILE *f)
76 {
77     int ofrefnum;
78
79     if (!oforks)
80         return;
81
82     for ( ofrefnum = 0; ofrefnum < nforks; ofrefnum++ ) {
83         if ( oforks[ ofrefnum ] != NULL ) {
84             fprintf( f, "%hu <%s>\n", ofrefnum, of_name(oforks[ ofrefnum ]));
85         }
86     }
87 }
88 #endif
89
90 int of_flush(const struct vol *vol)
91 {
92     int refnum;
93
94     if (!oforks)
95         return 0;
96
97     for ( refnum = 0; refnum < nforks; refnum++ ) {
98         if (oforks[ refnum ] != NULL && (oforks[refnum]->of_vol == vol) &&
99                 flushfork( oforks[ refnum ] ) < 0 ) {
100             LOG(log_error, logtype_afpd, "of_flush: %s", strerror(errno) );
101         }
102     }
103     return( 0 );
104 }
105
106 int of_rename(
107     const struct vol *vol,
108     struct ofork *s_of,
109     struct dir *olddir, const char *oldpath _U_,
110     struct dir *newdir, const char *newpath)
111 {
112     struct ofork *of, *next, *d_ofork;
113     int done = 0;
114
115     if (!s_of)
116         return AFP_OK;
117         
118     next = ofork_table[hashfn(&s_of->key)];
119     while ((of = next)) {
120         next = next->next; /* so we can unhash and still be all right. */
121
122         if (vol == of->of_vol && olddir == of->of_dir &&
123                  s_of->key.dev == of->key.dev && 
124                  s_of->key.inode == of->key.inode ) {
125             if (!done) {
126                 strlcpy( of_name(of), newpath, of->of_ad->ad_m_namelen);
127                 done = 1;
128             }
129             if (newdir != olddir) {
130                 of->of_d_prev->of_d_next = of->of_d_next;
131                 of->of_d_next->of_d_prev = of->of_d_prev;
132                 if (of->of_dir->d_ofork == of) {
133                     of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
134                 }           
135                 of->of_dir = newdir;
136                 if (!(d_ofork = newdir->d_ofork)) {
137                     newdir->d_ofork = of;
138                     of->of_d_next = of->of_d_prev = of;
139                 } else {
140                     of->of_d_next = d_ofork;
141                     of->of_d_prev = d_ofork->of_d_prev;
142                     of->of_d_prev->of_d_next = of;
143                     d_ofork->of_d_prev = of;
144                 }
145             }
146         }
147     }
148
149     return AFP_OK;
150 }
151
152 #define min(a,b)        ((a)<(b)?(a):(b))
153
154 struct ofork *
155 of_alloc(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
289     path->st_errno = 0;
290     path->st_valid = 1;
291     if ((ret = stat(path->u_name, &path->st)) < 0) {
292         LOG(log_debug, logtype_afpd, "of_stat: {'%s/%s': %s}",
293             getcwdpath(), path->u_name, strerror(errno));
294         path->st_errno = errno;
295     }
296     return ret;
297 }
298
299 /* -------------------------- 
300    stat the current directory.
301    stat(".") works even if "." is deleted thus
302    we have to stat ../name because we want to know if it's there
303 */
304 int of_statdir(struct vol *vol, struct path *path)
305 {
306     static char pathname[ MAXPATHLEN + 1] = "../";
307     int ret;
308     size_t len;
309     struct dir *dir;
310
311     if (*path->m_name) {
312         /* not curdir */
313         return of_stat (path);
314     }
315     path->st_errno = 0;
316     path->st_valid = 1;
317     /* FIXME, what about: we don't have r-x perm anymore ? */
318     len = blength(path->d_dir->d_u_name);
319     if (len > (MAXPATHLEN - 3))
320         len = MAXPATHLEN - 3;
321     strncpy(pathname + 3, cfrombstring(path->d_dir->d_u_name), len + 1);
322
323     LOG(log_debug, logtype_afpd, "of_statdir: stating: '%s'", pathname);
324
325     if (!(ret = stat(pathname, &path->st)))
326         return 0;
327         
328     path->st_errno = errno;
329
330     /* hmm, can't stat curdir anymore */
331     if (errno == EACCES && (dir = dirlookup(vol, curdir->d_pdid))) {
332        if (movecwd(vol, dir)) 
333            return -1;
334        path->st_errno = 0;
335        if ((ret = stat(cfrombstring(path->d_dir->d_u_name), &path->st)) < 0) 
336            path->st_errno = errno;
337     }
338
339     return ret;
340 }
341
342 /* -------------------------- */
343 struct ofork *of_findname(struct path *path)
344 {
345     struct ofork *of;
346     struct file_key key;
347     
348     if (!path->st_valid) {
349        of_stat(path);
350     }
351         
352     if (path->st_errno)
353         return NULL;
354
355     key.dev = path->st.st_dev;
356     key.inode = path->st.st_ino;
357
358     for (of = ofork_table[hashfn(&key)]; of; of = of->next) {
359         if (key.dev == of->key.dev && key.inode == of->key.inode ) {
360             return of;
361         }
362     }
363
364     return NULL;
365 }
366
367 void of_dealloc( struct ofork *of)
368 {
369     if (!oforks)
370         return;
371
372     of_unhash(of);
373
374     /* detach ofork */
375     of->of_d_prev->of_d_next = of->of_d_next;
376     of->of_d_next->of_d_prev = of->of_d_prev;
377     if (of->of_dir->d_ofork == of) {
378         of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
379     }
380
381     oforks[ of->of_refnum % nforks ] = NULL;
382
383     /* decrease refcount */
384     of->of_ad->ad_refcount--;
385
386     if ( of->of_ad->ad_refcount <= 0) {
387         free( of->of_ad->ad_m_name );
388         free( of->of_ad);
389     } else {/* someone's still using it. just free this user's locks */
390         ad_unlock(of->of_ad, of->of_refnum);
391     }
392
393     free( of );
394 }
395
396 /* --------------------------- */
397 int of_closefork(struct ofork *ofork)
398 {
399     struct timeval      tv;
400     int                 adflags, doflush = 0;
401     int                 ret;
402
403     adflags = 0;
404     if ((ofork->of_flags & AFPFORK_DATA) && (ad_data_fileno( ofork->of_ad ) != -1)) {
405             adflags |= ADFLAGS_DF;
406     }
407     if ( (ofork->of_flags & AFPFORK_OPEN) && ad_reso_fileno( ofork->of_ad ) != -1 ) {
408         adflags |= ADFLAGS_HF;
409         /*
410          * Only set the rfork's length if we're closing the rfork.
411          */
412         if ((ofork->of_flags & AFPFORK_RSRC)) {
413             ad_refresh( ofork->of_ad );
414             if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
415                 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
416                 doflush++;
417             }
418             if ( doflush ) {
419                  ad_flush( ofork->of_ad );
420             }
421         }
422     }
423     ret = 0;
424     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
425         ret = -1;
426     }
427  
428     of_dealloc( ofork );
429     return ret;
430 }
431
432 /* ----------------------
433
434 */
435 struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *ad)
436 {
437     struct ofork        *of;
438     struct adouble      *adp;
439
440     if ((of = of_findname(path))) {
441         adp = of->of_ad;
442     } else {
443         ad_init(ad, vol->v_adouble, vol->v_ad_options);
444         adp = ad;
445     }
446     return adp;
447 }
448
449 /* ---------------------- 
450    close all forks for a volume
451 */
452 void of_closevol(const struct vol *vol)
453 {
454     int refnum;
455
456     if (!oforks)
457         return;
458
459     for ( refnum = 0; refnum < nforks; refnum++ ) {
460         if (oforks[ refnum ] != NULL && oforks[refnum]->of_vol == vol) {
461             if (of_closefork( oforks[ refnum ]) < 0 ) {
462                 LOG(log_error, logtype_afpd, "of_closevol: %s", strerror(errno) );
463             }
464         }
465     }
466     return;
467 }
468