~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to etc/afpd/ofork.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: ofork.c,v 1.19.2.1 2003/06/09 14:53:16 srittau 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
#if 0
 
41
    unsigned long i = 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
            strncpy( of->of_name, newpath, of->of_namelen);
 
119
            if (newdir != olddir) {
 
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
            }
 
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
    
 
282
    if (st == NULL) {
 
283
        st = &buffer;
 
284
        if (stat(name, st) < 0)
 
285
            return NULL;
 
286
    }
 
287
    key.dev = st->st_dev;
 
288
    key.inode = st->st_ino;
 
289
 
 
290
    for (of = ofork_table[hashfn(&key)]; of; of = of->next) {
 
291
        if (key.dev == of->key.dev && key.inode == of->key.inode ) {
 
292
            return of;
 
293
        }
 
294
    }
 
295
 
 
296
    return NULL;
 
297
}
 
298
 
 
299
void of_dealloc( of )
 
300
struct ofork    *of;
 
301
{
 
302
    if (!oforks)
 
303
        return;
 
304
 
 
305
    of_unhash(of);
 
306
 
 
307
    /* detach ofork */
 
308
    of->of_d_prev->of_d_next = of->of_d_next;
 
309
    of->of_d_next->of_d_prev = of->of_d_prev;
 
310
    if (of->of_dir->d_ofork == of) {
 
311
        of->of_dir->d_ofork = (of == of->of_d_next) ? NULL : of->of_d_next;
 
312
    }
 
313
 
 
314
    oforks[ of->of_refnum % nforks ] = NULL;
 
315
    free( of->of_name );
 
316
 
 
317
    /* decrease refcount */
 
318
    of->of_ad->ad_refcount--;
 
319
 
 
320
    if ( of->of_ad->ad_refcount <= 0) {
 
321
        free( of->of_ad);
 
322
    } else {/* someone's still using it. just free this user's locks */
 
323
        ad_unlock(of->of_ad, of->of_refnum);
 
324
    }
 
325
 
 
326
    free( of );
 
327
}