~ubuntu-branches/debian/lenny/netatalk/lenny

« back to all changes in this revision

Viewing changes to etc/afpd/fork.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: fork.c,v 1.37.2.3 2003/11/20 17:21:01 bfernhomberg Exp $
 
3
 *
 
4
 * Copyright (c) 1990,1993 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
#ifdef HAVE_UNISTD_H
 
14
#include <unistd.h>
 
15
#endif /* HAVE_UNISTD_H */
 
16
#ifdef HAVE_FCNTL_H
 
17
#include <fcntl.h>
 
18
#endif /* HAVE_FCNTL_H */
 
19
#include <dirent.h>
 
20
#include <string.h>
 
21
#include <errno.h>
 
22
#include <atalk/logger.h>
 
23
 
 
24
#include <sys/param.h>
 
25
#include <sys/stat.h>
 
26
#include <sys/types.h>
 
27
#include <sys/time.h>
 
28
#include <sys/socket.h>
 
29
 
 
30
#include <netatalk/endian.h>
 
31
#include <netatalk/at.h>
 
32
 
 
33
#include <atalk/dsi.h>
 
34
#include <atalk/atp.h>
 
35
#include <atalk/asp.h>
 
36
#include <atalk/afp.h>
 
37
#include <atalk/adouble.h>
 
38
#include <atalk/util.h>
 
39
#ifdef CNID_DB
 
40
#include <atalk/cnid.h>
 
41
#endif
 
42
 
 
43
#include "fork.h"
 
44
#include "file.h"
 
45
#include "filedir.h"
 
46
#include "globals.h"
 
47
#include "directory.h"
 
48
#include "desktop.h"
 
49
#include "volume.h"
 
50
 
 
51
#define BYTELOCK_MAX 0x7FFFFFFFU
 
52
 
 
53
struct ofork            *writtenfork;
 
54
extern int getmetadata(struct vol *vol,
 
55
                 u_int16_t bitmap,
 
56
                 char *path, struct dir *dir, struct stat *st,
 
57
                 char *buf, int *buflen, struct adouble *adp, int attrbits );
 
58
 
 
59
static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
 
60
struct ofork    *ofork;
 
61
u_int16_t               bitmap;
 
62
char            *buf;
 
63
int                     *buflen;
 
64
const u_int16_t     attrbits;
 
65
{
 
66
    struct stat         st;
 
67
    char                *upath;
 
68
    u_int32_t           aint;
 
69
 
 
70
    struct adouble      *adp;
 
71
    struct dir          *dir;
 
72
    struct vol          *vol;
 
73
    
 
74
    if ( ad_hfileno( ofork->of_ad ) == -1 ) {
 
75
        adp = NULL;
 
76
    } else {
 
77
        aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
 
78
        if ( ad_refresh( ofork->of_ad ) < 0 ) {
 
79
            LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
 
80
            return( AFPERR_PARAM );
 
81
        }
 
82
        /* See afp_closefork() for why this is bad */
 
83
        ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
 
84
        adp = ofork->of_ad;
 
85
    }
 
86
 
 
87
    /* can only get the length of the opened fork */
 
88
    if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
 
89
            ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
 
90
        return( AFPERR_BITMAP );
 
91
    }
 
92
 
 
93
    vol = ofork->of_vol;
 
94
    dir = ofork->of_dir;
 
95
 
 
96
    if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
 
97
                    (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
 
98
                    (1 << FILPBIT_BDATE))) {
 
99
        if ( ad_dfileno( ofork->of_ad ) == -1 ) {
 
100
            upath = mtoupath(vol, ofork->of_name);
 
101
            if (movecwd(vol, dir) < 0)
 
102
                return( AFPERR_NOOBJ );
 
103
            if ( stat( upath, &st ) < 0 )
 
104
                return( AFPERR_NOOBJ );
 
105
        } else {
 
106
            if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
 
107
                return( AFPERR_BITMAP );
 
108
            }
 
109
        }
 
110
    }
 
111
    return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );    
 
112
}
 
113
 
 
114
/* -------------------------
 
115
*/
 
116
#define SHARE 0
 
117
#define EXCL  1
 
118
static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
 
119
{
 
120
    int lockmode;
 
121
    int lockop;
 
122
    
 
123
    /* NOTE: we can't write lock a read-only file. on those, we just
 
124
     * make sure that we have a read lock set. that way, we at least prevent
 
125
     * someone else from really setting a deny read/write on the file. 
 
126
     */
 
127
    lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
 
128
    lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
 
129
    
 
130
    return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
 
131
                        what, 1, ofrefnum);
 
132
}
 
133
 
 
134
/* -------------------------
 
135
*/
 
136
extern int ad_testlock(struct adouble *adp, int eid, int off);
 
137
 
 
138
static int getforkmode(struct adouble *adp, int eid, int what)
 
139
{
 
140
    return ad_testlock(adp, eid,  what);
 
141
}
 
142
 
 
143
/* -------------------------- 
 
144
   a lot of races, some can be remove. but I try first to get the semantic right
 
145
*/
 
146
 
 
147
static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
 
148
{
 
149
    int ret;
 
150
    int readset;
 
151
    int writeset;
 
152
    int denyreadset;
 
153
    int denywriteset;
 
154
    int mode;    
 
155
 
 
156
    if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
 
157
        return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
 
158
    }
 
159
 
 
160
    if ((access & (OPENACC_RD | OPENACC_DRD))) {
 
161
        if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
 
162
            return readset;
 
163
        if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
 
164
            return denyreadset;
 
165
 
 
166
        if ((access & OPENACC_RD) && denyreadset) {
 
167
            errno = EACCES;
 
168
            return -1;
 
169
        }
 
170
        if ((access & OPENACC_DRD) && readset) {
 
171
            errno = EACCES;
 
172
            return -1;
 
173
        }   
 
174
        /* boolean logic is not enough, because getforkmode is not always telling the
 
175
         * true 
 
176
         */
 
177
        mode = ((access & OPENACC_DRD))?EXCL: SHARE;
 
178
        if ((access & OPENACC_RD)) {
 
179
            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
 
180
            if (ret)
 
181
                return ret;
 
182
        }
 
183
        if ((access & OPENACC_DRD)) {
 
184
            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
 
185
            if (ret)
 
186
                return ret;
 
187
        }
 
188
    }
 
189
    /* ------------same for writing -------------- */
 
190
    if ((access & (OPENACC_WR | OPENACC_DWR))) {
 
191
        if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
 
192
            return writeset;
 
193
        if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
 
194
            return denywriteset;
 
195
 
 
196
        if ((access & OPENACC_WR) && denywriteset) {
 
197
            errno = EACCES;
 
198
            return -1;
 
199
        }
 
200
        if ((access & OPENACC_DWR) && writeset) {
 
201
            errno = EACCES;
 
202
            return -1;
 
203
        }   
 
204
        mode = ((access & OPENACC_DWR))?EXCL: SHARE;
 
205
        if ((access & OPENACC_WR)) {
 
206
            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
 
207
            if (ret)
 
208
                return ret;
 
209
        }
 
210
        if ((access & OPENACC_DWR)) {
 
211
            ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
 
212
            if (ret)
 
213
                return ret;
 
214
        }
 
215
    }
 
216
    return 0;
 
217
}
 
218
 
 
219
/* ----------------------- */    
 
220
int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
 
221
AFPObj      *obj;
 
222
char    *ibuf, *rbuf;
 
223
int             ibuflen, *rbuflen;
 
224
{
 
225
    struct vol          *vol;
 
226
    struct dir          *dir;
 
227
    struct ofork        *ofork, *opened;
 
228
    struct adouble      *adsame = NULL;
 
229
    int                 buflen, ret, adflags, eid;
 
230
    u_int32_t           did;
 
231
    u_int16_t           vid, bitmap, access, ofrefnum, attrbits = 0;
 
232
    char                fork, *path, *upath;
 
233
    struct stat         st;
 
234
    u_int16_t           bshort;
 
235
 
 
236
    ibuf++;
 
237
    fork = *ibuf++;
 
238
    memcpy(&vid, ibuf, sizeof( vid ));
 
239
    ibuf += sizeof(vid);
 
240
 
 
241
    *rbuflen = 0;
 
242
    if (( vol = getvolbyvid( vid )) == NULL ) {
 
243
        return( AFPERR_PARAM );
 
244
    }
 
245
 
 
246
    memcpy(&did, ibuf, sizeof( did ));
 
247
    ibuf += sizeof( int );
 
248
 
 
249
    if (( dir = dirlookup( vol, did )) == NULL ) {
 
250
        return( AFPERR_NOOBJ );
 
251
    }
 
252
 
 
253
    memcpy(&bitmap, ibuf, sizeof( bitmap ));
 
254
    bitmap = ntohs( bitmap );
 
255
    ibuf += sizeof( bitmap );
 
256
    memcpy(&access, ibuf, sizeof( access ));
 
257
    access = ntohs( access );
 
258
    ibuf += sizeof( access );
 
259
 
 
260
    if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
 
261
        return AFPERR_VLOCK;
 
262
    }
 
263
 
 
264
    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
 
265
        return( AFPERR_NOOBJ );
 
266
    }
 
267
 
 
268
    if ( fork == OPENFORK_DATA ) {
 
269
        eid = ADEID_DFORK;
 
270
        adflags = ADFLAGS_DF|ADFLAGS_HF;
 
271
    } else {
 
272
        eid = ADEID_RFORK;
 
273
        adflags = ADFLAGS_HF;
 
274
    }
 
275
 
 
276
    upath = mtoupath(vol, path);
 
277
    if (check_access(upath, access ) < 0) {
 
278
        return AFPERR_ACCESS;
 
279
    }
 
280
 
 
281
    /* stat() data fork */
 
282
    if (stat(upath, &st) < 0) {
 
283
        switch ( errno ) {
 
284
        case ENOENT:
 
285
            return AFPERR_NOOBJ;
 
286
        case EACCES:
 
287
            return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
 
288
        default:
 
289
            LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
 
290
            return AFPERR_PARAM;
 
291
        }
 
292
    }
 
293
 
 
294
    /* XXX: this probably isn't the best way to do this. the already
 
295
       open bits should really be set if the fork is opened by any
 
296
       program, not just this one. however, that's problematic to do
 
297
       if we can't write lock files somewhere. opened is also passed to 
 
298
       ad_open so that we can keep file locks together.
 
299
       FIXME: add the fork we are opening? 
 
300
    */
 
301
    if ((opened = of_findname(upath, &st))) {
 
302
        attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
 
303
        attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
 
304
                   
 
305
        adsame = opened->of_ad;
 
306
    }
 
307
 
 
308
    if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
 
309
                           adsame, &st)) == NULL ) {
 
310
        return( AFPERR_NFILE );
 
311
    }
 
312
 
 
313
    ret = AFPERR_NOOBJ;
 
314
    if (access & OPENACC_WR) {
 
315
        /* try opening in read-write mode */
 
316
        if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
 
317
            switch ( errno ) {
 
318
            case EROFS:
 
319
                ret = AFPERR_VLOCK;
 
320
            case EACCES:
 
321
                goto openfork_err;
 
322
                break;
 
323
            case ENOENT:
 
324
                if (fork == OPENFORK_DATA) {
 
325
                    if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
 
326
                        goto openfork_err;
 
327
                    }
 
328
                    adflags = ADFLAGS_DF;
 
329
                } else {
 
330
                    /* here's the deal. we only try to create the resource
 
331
                    * fork if the user wants to open it for write acess. */
 
332
                    if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
 
333
                        goto openfork_err;
 
334
                }
 
335
                break;
 
336
            case EMFILE :
 
337
            case ENFILE :
 
338
                ret = AFPERR_NFILE;
 
339
                goto openfork_err;
 
340
                break;
 
341
            case EISDIR :
 
342
                ret = AFPERR_BADTYPE;
 
343
                goto openfork_err;
 
344
                break;
 
345
            default:
 
346
                LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
 
347
                ret = AFPERR_PARAM;
 
348
                goto openfork_err;
 
349
                break;
 
350
            }
 
351
        }
 
352
    } else {
 
353
        /* try opening in read-only mode */
 
354
        ret = AFPERR_NOOBJ;
 
355
        if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
 
356
            switch ( errno ) {
 
357
            case EROFS:
 
358
                ret = AFPERR_VLOCK;
 
359
            case EACCES:
 
360
                /* check for a read-only data fork */
 
361
                if ((adflags != ADFLAGS_HF) &&
 
362
                        (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
 
363
                    goto openfork_err;
 
364
 
 
365
                adflags = ADFLAGS_DF;
 
366
                break;
 
367
            case ENOENT:
 
368
                /* see if client asked for the data fork */
 
369
                if (fork == OPENFORK_DATA) {
 
370
                    if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
 
371
                        goto openfork_err;
 
372
                    }
 
373
                    adflags = ADFLAGS_DF;
 
374
                }
 
375
                break;
 
376
            case EMFILE :
 
377
            case ENFILE :
 
378
                ret = AFPERR_NFILE;
 
379
                goto openfork_err;
 
380
                break;
 
381
            case EISDIR :
 
382
                ret = AFPERR_BADTYPE;
 
383
                goto openfork_err;
 
384
                break;
 
385
            default:
 
386
                LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
 
387
                goto openfork_err;
 
388
                break;
 
389
            }
 
390
        }
 
391
    }
 
392
 
 
393
    if ((adflags & ADFLAGS_HF) &&
 
394
            (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
 
395
        ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
 
396
        memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
 
397
               ad_getentrylen( ofork->of_ad, ADEID_NAME ));
 
398
        ad_flush( ofork->of_ad, adflags );
 
399
    }
 
400
 
 
401
    if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
 
402
                              &buflen, attrbits )) != AFP_OK ) {
 
403
        ad_close( ofork->of_ad, adflags );
 
404
        goto openfork_err;
 
405
    }
 
406
 
 
407
    *rbuflen = buflen + 2 * sizeof( u_int16_t );
 
408
    bitmap = htons( bitmap );
 
409
    memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
 
410
    rbuf += sizeof( u_int16_t );
 
411
 
 
412
    /* check  WriteInhibit bit, the test is done here, after some Mac trafic capture */
 
413
    ad_getattr(ofork->of_ad, &bshort);
 
414
    if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
 
415
        ad_close( ofork->of_ad, adflags );
 
416
        of_dealloc( ofork );
 
417
        ofrefnum = 0;
 
418
        memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
 
419
        return(AFPERR_OLOCK);
 
420
    }
 
421
 
 
422
    /*
 
423
     * synchronization locks:
 
424
     */
 
425
 
 
426
    /* don't try to lock non-existent rforks. */
 
427
    if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
 
428
 
 
429
        ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
 
430
        /* can we access the fork? */
 
431
        if (ret < 0) {
 
432
            ret = errno;
 
433
            ad_close( ofork->of_ad, adflags );
 
434
            of_dealloc( ofork );
 
435
            switch (ret) {
 
436
            case EAGAIN: /* return data anyway */
 
437
            case EACCES:
 
438
            case EINVAL:
 
439
                ofrefnum = 0;
 
440
                memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
 
441
                return( AFPERR_DENYCONF );
 
442
                break;
 
443
            default:
 
444
                *rbuflen = 0;
 
445
                LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
 
446
                return( AFPERR_PARAM );
 
447
            }
 
448
        }
 
449
        if ((access & OPENACC_WR))
 
450
            ofork->of_flags |= AFPFORK_ACCWR;
 
451
        if ((access & OPENACC_RD))
 
452
            ofork->of_flags |= AFPFORK_ACCRD;
 
453
    }
 
454
 
 
455
    memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
 
456
    return( AFP_OK );
 
457
 
 
458
openfork_err:
 
459
    of_dealloc( ofork );
 
460
    if (errno == EACCES)
 
461
        return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
 
462
    return ret;
 
463
}
 
464
 
 
465
int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
 
466
AFPObj      *obj;
 
467
char    *ibuf, *rbuf;
 
468
int             ibuflen, *rbuflen;
 
469
{
 
470
    struct ofork        *ofork;
 
471
    int32_t             size;
 
472
    u_int16_t           ofrefnum, bitmap;
 
473
    int                 err;
 
474
 
 
475
    ibuf += 2;
 
476
    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
477
    ibuf += sizeof( ofrefnum );
 
478
    memcpy(&bitmap, ibuf, sizeof(bitmap));
 
479
    bitmap = ntohs(bitmap);
 
480
    ibuf += sizeof( bitmap );
 
481
    memcpy(&size, ibuf, sizeof( size ));
 
482
    size = ntohl( size );
 
483
 
 
484
    *rbuflen = 0;
 
485
    if (( ofork = of_find( ofrefnum )) == NULL ) {
 
486
        LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
 
487
        return( AFPERR_PARAM );
 
488
    }
 
489
 
 
490
    if (ofork->of_vol->v_flags & AFPVOL_RO)
 
491
        return AFPERR_VLOCK;
 
492
 
 
493
    if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
 
494
        return AFPERR_ACCESS;
 
495
 
 
496
    if (size < 0)
 
497
        return AFPERR_PARAM;
 
498
 
 
499
    if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
 
500
        err = ad_dtruncate( ofork->of_ad, size );
 
501
        if (err < 0)
 
502
            goto afp_setfork_err;
 
503
    } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
 
504
               (ofork->of_flags & AFPFORK_RSRC)) {
 
505
        ad_refresh( ofork->of_ad );
 
506
        err = ad_rtruncate(ofork->of_ad, size);
 
507
        if (err < 0)
 
508
            goto afp_setfork_err;
 
509
 
 
510
        if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
 
511
            LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
 
512
                strerror(errno) );
 
513
            return( AFPERR_PARAM );
 
514
        }
 
515
    } else
 
516
        return AFPERR_BITMAP;
 
517
 
 
518
#ifdef AFS
 
519
    if ( flushfork( ofork ) < 0 ) {
 
520
        LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
 
521
    }
 
522
#endif /* AFS */
 
523
 
 
524
    return( AFP_OK );
 
525
 
 
526
afp_setfork_err:
 
527
    if (err == -2)
 
528
        return AFPERR_LOCK;
 
529
    else {
 
530
        switch (errno) {
 
531
        case EROFS:
 
532
            return AFPERR_VLOCK;
 
533
        case EPERM:
 
534
        case EACCES:
 
535
            return AFPERR_ACCESS;
 
536
        case EDQUOT:
 
537
        case EFBIG:
 
538
        case ENOSPC:
 
539
            return AFPERR_DFULL;
 
540
        default:
 
541
            return AFPERR_PARAM;
 
542
        }
 
543
    }
 
544
}
 
545
 
 
546
/* for this to work correctly, we need to check for locks before each
 
547
 * read and write. that's most easily handled by always doing an
 
548
 * appropriate check before each ad_read/ad_write. other things
 
549
 * that can change files like truncate are handled internally to those
 
550
 * functions. 
 
551
 */
 
552
#define ENDBIT(a)  ((a) & 0x80)
 
553
#define UNLOCKBIT(a) ((a) & 0x01)
 
554
int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
 
555
AFPObj      *obj;
 
556
char    *ibuf, *rbuf;
 
557
int             ibuflen, *rbuflen;
 
558
{
 
559
    struct ofork        *ofork;
 
560
    int32_t             offset, length;
 
561
    int                 eid;
 
562
    u_int16_t           ofrefnum;
 
563
    u_int8_t            flags;
 
564
 
 
565
    *rbuflen = 0;
 
566
 
 
567
    /* figure out parameters */
 
568
    ibuf++;
 
569
    flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
 
570
    ibuf++;
 
571
    memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
 
572
    ibuf += sizeof(ofrefnum);
 
573
 
 
574
    if (( ofork = of_find( ofrefnum )) == NULL ) {
 
575
        LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
 
576
        return( AFPERR_PARAM );
 
577
    }
 
578
 
 
579
    if ( ofork->of_flags & AFPFORK_DATA) {
 
580
        eid = ADEID_DFORK;
 
581
    } else if (ofork->of_flags & AFPFORK_RSRC) {
 
582
        eid = ADEID_RFORK;
 
583
    } else
 
584
        return AFPERR_PARAM;
 
585
 
 
586
    memcpy(&offset, ibuf, sizeof( offset ));
 
587
    offset = ntohl(offset);
 
588
    ibuf += sizeof(offset);
 
589
 
 
590
    memcpy(&length, ibuf, sizeof( length ));
 
591
    length = ntohl(length);
 
592
    if (length == 0xFFFFFFFF)
 
593
        length = BYTELOCK_MAX;
 
594
    else if (length <= 0) {
 
595
        return AFPERR_PARAM;
 
596
    } else if ((length >= AD_FILELOCK_BASE) &&
 
597
               (ad_hfileno(ofork->of_ad) == -1))
 
598
        return AFPERR_LOCK;
 
599
 
 
600
    if (ENDBIT(flags))
 
601
        offset += ad_size(ofork->of_ad, eid);
 
602
 
 
603
    if (offset < 0)    /* error if we have a negative offset */
 
604
        return AFPERR_PARAM;
 
605
 
 
606
    /* if the file is a read-only file, we use read locks instead of
 
607
     * write locks. that way, we can prevent anyone from initiating
 
608
     * a write lock. */
 
609
    if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
 
610
                ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
 
611
                 ADLOCK_WR : ADLOCK_RD), offset, length,
 
612
                ofork->of_refnum) < 0) {
 
613
        switch (errno) {
 
614
        case EACCES:
 
615
        case EAGAIN:
 
616
            return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
 
617
            break;
 
618
        case ENOLCK:
 
619
            return AFPERR_NLOCK;
 
620
            break;
 
621
        case EINVAL:
 
622
            return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
 
623
            break;
 
624
        case EBADF:
 
625
        default:
 
626
            return AFPERR_PARAM;
 
627
            break;
 
628
        }
 
629
    }
 
630
 
 
631
    offset = htonl(offset);
 
632
    memcpy(rbuf, &offset, sizeof( offset ));
 
633
    *rbuflen = sizeof( offset );
 
634
    return( AFP_OK );
 
635
}
 
636
#undef UNLOCKBIT
 
637
 
 
638
 
 
639
static __inline__ int crlf( of )
 
640
struct ofork    *of;
 
641
{
 
642
    struct extmap       *em;
 
643
 
 
644
    if ( ad_hfileno( of->of_ad ) == -1 ||
 
645
            memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
 
646
                    8) == 0 ) {
 
647
        if (( em = getextmap( of->of_name )) == NULL ||
 
648
                memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
 
649
            return( 1 );
 
650
        } else {
 
651
            return( 0 );
 
652
        }
 
653
    } else {
 
654
        if ( memcmp( ufinderi,
 
655
                     ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
 
656
            return( 1 );
 
657
        } else {
 
658
            return( 0 );
 
659
        }
 
660
    }
 
661
}
 
662
 
 
663
 
 
664
static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
 
665
                                    int offset, u_char nlmask,
 
666
                                    u_char nlchar, char *rbuf,
 
667
                                    int *rbuflen, const int xlate)
 
668
{
 
669
    ssize_t cc;
 
670
    int eof = 0;
 
671
    char *p, *q;
 
672
 
 
673
    cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
 
674
    if ( cc < 0 ) {
 
675
        LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
 
676
        *rbuflen = 0;
 
677
        return( AFPERR_PARAM );
 
678
    }
 
679
    if ( cc < *rbuflen ) {
 
680
        eof = 1;
 
681
    }
 
682
 
 
683
    /*
 
684
     * Do Newline check.
 
685
     */
 
686
    if ( nlmask != 0 ) {
 
687
        for ( p = rbuf, q = p + cc; p < q; ) {
 
688
            if (( *p++ & nlmask ) == nlchar ) {
 
689
                break;
 
690
            }
 
691
        }
 
692
        if ( p != q ) {
 
693
            cc = p - rbuf;
 
694
            eof = 0;
 
695
        }
 
696
    }
 
697
 
 
698
    /*
 
699
     * If this file is of type TEXT, then swap \012 to \015.
 
700
     */
 
701
    if (xlate) {
 
702
        for ( p = rbuf, q = p + cc; p < q; p++ ) {
 
703
            if ( *p == '\012' ) {
 
704
                *p = '\015';
 
705
            } else if ( *p == '\015' ) {
 
706
                *p = '\012';
 
707
            }
 
708
 
 
709
        }
 
710
    }
 
711
 
 
712
    *rbuflen = cc;
 
713
    if ( eof ) {
 
714
        return( AFPERR_EOF );
 
715
    }
 
716
    return AFP_OK;
 
717
}
 
718
 
 
719
/* -----------------------------
 
720
 * with ddp, afp_read can return fewer bytes than in reqcount 
 
721
 * so return EOF only if read actually past end of file not
 
722
 * if offset +reqcount > size of file
 
723
 * e.g.:
 
724
 * getfork size ==> 10430
 
725
 * read fork offset 0 size 10752 ????  ==> 4264 bytes (without EOF)
 
726
 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
 
727
 * read fork offset 9248 size 1508 ==> 1182 (EOF)
 
728
 * 10752 is a bug in Mac 7.5.x finder 
 
729
 *
 
730
 * with dsi, should we check that reqcount < server quantum? 
 
731
*/
 
732
int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
 
733
AFPObj      *obj;
 
734
char    *ibuf, *rbuf;
 
735
int             ibuflen, *rbuflen;
 
736
{
 
737
    struct ofork        *ofork;
 
738
    off_t               size;
 
739
    int32_t             offset, saveoff, reqcount, savereqcount;
 
740
    int                 cc, err, eid, xlate = 0;
 
741
    u_int16_t           ofrefnum;
 
742
    u_char              nlmask, nlchar;
 
743
 
 
744
    ibuf += 2;
 
745
    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
746
    ibuf += sizeof( u_short );
 
747
 
 
748
    if (( ofork = of_find( ofrefnum )) == NULL ) {
 
749
        LOG(log_error, logtype_afpd, "afp_read: of_find");
 
750
        err = AFPERR_PARAM;
 
751
        goto afp_read_err;
 
752
    }
 
753
 
 
754
    if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
 
755
        err = AFPERR_ACCESS;
 
756
        goto afp_read_err;
 
757
    }
 
758
 
 
759
    memcpy(&offset, ibuf, sizeof( offset ));
 
760
    offset = ntohl( offset );
 
761
    ibuf += sizeof( offset );
 
762
    memcpy(&reqcount, ibuf, sizeof( reqcount ));
 
763
    reqcount = ntohl( reqcount );
 
764
    ibuf += sizeof( reqcount );
 
765
 
 
766
    nlmask = *ibuf++;
 
767
    nlchar = *ibuf++;
 
768
 
 
769
    /* if we wanted to be picky, we could add in the following
 
770
     * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
 
771
     */
 
772
    if (reqcount < 0 || offset < 0) {
 
773
        err = AFPERR_PARAM;
 
774
        goto afp_read_err;
 
775
    }
 
776
 
 
777
    if ( ofork->of_flags & AFPFORK_DATA) {
 
778
        eid = ADEID_DFORK;
 
779
        xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
 
780
    } else if (ofork->of_flags & AFPFORK_RSRC) {
 
781
        eid = ADEID_RFORK;
 
782
    } else { /* fork wasn't opened. this should never really happen. */
 
783
        err = AFPERR_ACCESS;
 
784
        goto afp_read_err;
 
785
    }
 
786
 
 
787
    /* zero request count */
 
788
    err = AFP_OK;
 
789
    if (!reqcount) {
 
790
        goto afp_read_err;
 
791
    }
 
792
 
 
793
    /* reqcount isn't always truthful. we need to deal with that. */
 
794
    size = ad_size(ofork->of_ad, eid);
 
795
 
 
796
    if (offset >= size) {
 
797
        err = AFPERR_EOF;
 
798
        goto afp_read_err;
 
799
    }
 
800
 
 
801
    savereqcount = reqcount;
 
802
    saveoff = offset;
 
803
    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
 
804
        err = AFPERR_LOCK;
 
805
        goto afp_read_err;
 
806
    }
 
807
 
 
808
#define min(a,b)        ((a)<(b)?(a):(b))
 
809
    *rbuflen = min( reqcount, *rbuflen );
 
810
    err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
 
811
                    xlate);
 
812
    if (err < 0)
 
813
        goto afp_read_done;
 
814
 
 
815
    /* dsi can stream requests. we can only do this if we're not checking
 
816
     * for an end-of-line character. oh well. */
 
817
    if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
 
818
        DSI *dsi = obj->handle;
 
819
 
 
820
        if (obj->options.flags & OPTION_DEBUG) {
 
821
            printf( "(read) reply: %d/%d, %d\n", *rbuflen,
 
822
                    reqcount, dsi->clientID);
 
823
            bprint(rbuf, *rbuflen);
 
824
        }
 
825
        /* subtract off the offset */
 
826
        size -= offset;
 
827
        if (reqcount > size) {
 
828
           reqcount = size;
 
829
           err = AFPERR_EOF;
 
830
        }
 
831
 
 
832
        offset += *rbuflen;
 
833
 
 
834
        /* dsi_readinit() returns size of next read buffer. by this point,
 
835
         * we know that we're sending some data. if we fail, something
 
836
         * horrible happened. */
 
837
        if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
 
838
            goto afp_read_exit;
 
839
 
 
840
        /* due to the nature of afp packets, we have to exit if we get
 
841
           an error. we can't do this with translation on. */
 
842
#ifdef HAVE_SENDFILE_READ
 
843
        if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
 
844
            if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
 
845
                            dsi->datasize) < 0) {
 
846
                if (errno == EINVAL)
 
847
                    goto afp_read_loop;
 
848
                else {
 
849
                    LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
 
850
                    goto afp_read_exit;
 
851
                }
 
852
            }
 
853
 
 
854
            dsi_readdone(dsi);
 
855
            goto afp_read_done;
 
856
        }
 
857
 
 
858
afp_read_loop:
 
859
#endif /* HAVE_SENDFILE_READ */
 
860
 
 
861
        /* fill up our buffer. */
 
862
        while (*rbuflen > 0) {
 
863
            cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
 
864
                           rbuflen, xlate);
 
865
            if (cc < 0)
 
866
                goto afp_read_exit;
 
867
 
 
868
            offset += *rbuflen;
 
869
            if (obj->options.flags & OPTION_DEBUG) {
 
870
                printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
 
871
                bprint(rbuf, *rbuflen);
 
872
            }
 
873
 
 
874
            /* dsi_read() also returns buffer size of next allocation */
 
875
            cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
 
876
            if (cc < 0)
 
877
                goto afp_read_exit;
 
878
            *rbuflen = cc;
 
879
        }
 
880
        dsi_readdone(dsi);
 
881
        goto afp_read_done;
 
882
 
 
883
afp_read_exit:
 
884
        LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
 
885
        dsi_readdone(dsi);
 
886
        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
 
887
        obj->exit(1);
 
888
    }
 
889
 
 
890
afp_read_done:
 
891
    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
 
892
    return err;
 
893
 
 
894
afp_read_err:
 
895
    *rbuflen = 0;
 
896
    return err;
 
897
}
 
898
 
 
899
int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
 
900
AFPObj      *obj;
 
901
char    *ibuf, *rbuf;
 
902
int             ibuflen, *rbuflen;
 
903
{
 
904
    struct vol *vol;
 
905
    u_int16_t vid;
 
906
 
 
907
    *rbuflen = 0;
 
908
    ibuf += 2;
 
909
 
 
910
    memcpy(&vid, ibuf, sizeof(vid));
 
911
    if (( vol = getvolbyvid( vid )) == NULL ) {
 
912
        return( AFPERR_PARAM );
 
913
    }
 
914
 
 
915
    of_flush(vol);
 
916
    return( AFP_OK );
 
917
}
 
918
 
 
919
int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
 
920
AFPObj      *obj;
 
921
char    *ibuf, *rbuf;
 
922
int             ibuflen, *rbuflen;
 
923
{
 
924
    struct ofork        *ofork;
 
925
    u_int16_t           ofrefnum;
 
926
 
 
927
    *rbuflen = 0;
 
928
    ibuf += 2;
 
929
    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
930
 
 
931
    if (( ofork = of_find( ofrefnum )) == NULL ) {
 
932
        LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d)", ofrefnum);
 
933
        return( AFPERR_PARAM );
 
934
    }
 
935
 
 
936
    if ( flushfork( ofork ) < 0 ) {
 
937
        LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
 
938
    }
 
939
 
 
940
    return( AFP_OK );
 
941
}
 
942
 
 
943
/* this is very similar to closefork */
 
944
int flushfork( ofork )
 
945
struct ofork    *ofork;
 
946
{
 
947
    struct timeval tv;
 
948
    int len, err = 0, doflush = 0;
 
949
 
 
950
    if ( ad_dfileno( ofork->of_ad ) != -1 &&
 
951
            fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
 
952
        LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
 
953
            ad_dfileno(ofork->of_ad), strerror(errno) );
 
954
        err = -1;
 
955
    }
 
956
 
 
957
    if ( ad_hfileno( ofork->of_ad ) != -1 ) {
 
958
 
 
959
        /* read in the rfork length */
 
960
        len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
 
961
        ad_refresh(ofork->of_ad);
 
962
 
 
963
        /* set the date if we're dirty */
 
964
        if ((ofork->of_flags & AFPFORK_DIRTY) &&
 
965
                (gettimeofday(&tv, NULL) == 0)) {
 
966
            ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
 
967
            ofork->of_flags &= ~AFPFORK_DIRTY;
 
968
            doflush++;
 
969
        }
 
970
 
 
971
        /* if we're actually flushing this fork, make sure to set the
 
972
         * length. otherwise, just use the stored length */
 
973
        if ((ofork->of_flags & AFPFORK_RSRC) &&
 
974
                (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
 
975
            ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
 
976
            doflush++;
 
977
        }
 
978
 
 
979
 
 
980
        /* flush the header (if it is a resource fork) */
 
981
        if (ofork->of_flags & AFPFORK_RSRC)
 
982
            if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
 
983
                err = -1;
 
984
 
 
985
        if (fsync( ad_hfileno( ofork->of_ad )) < 0)
 
986
            err = -1;
 
987
 
 
988
        if (err < 0)
 
989
            LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
 
990
                ad_hfileno(ofork->of_ad), strerror(errno) );
 
991
    }
 
992
 
 
993
    return( err );
 
994
}
 
995
 
 
996
int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
 
997
AFPObj      *obj;
 
998
char    *ibuf, *rbuf;
 
999
int             ibuflen, *rbuflen;
 
1000
{
 
1001
    struct ofork        *ofork;
 
1002
    struct timeval      tv;
 
1003
    int                 adflags, aint, doflush = 0;
 
1004
    u_int16_t           ofrefnum;
 
1005
 
 
1006
    *rbuflen = 0;
 
1007
    ibuf += 2;
 
1008
    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
1009
 
 
1010
    if (( ofork = of_find( ofrefnum )) == NULL ) {
 
1011
        LOG(log_error, logtype_afpd, "afp_closefork: of_find");
 
1012
        return( AFPERR_PARAM );
 
1013
    }
 
1014
 
 
1015
    adflags = 0;
 
1016
    if ((ofork->of_flags & AFPFORK_DATA) &&
 
1017
            (ad_dfileno( ofork->of_ad ) != -1)) {
 
1018
        adflags |= ADFLAGS_DF;
 
1019
    }
 
1020
 
 
1021
    if ( ad_hfileno( ofork->of_ad ) != -1 ) {
 
1022
        adflags |= ADFLAGS_HF;
 
1023
 
 
1024
        aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
 
1025
        ad_refresh( ofork->of_ad );
 
1026
        if ((ofork->of_flags & AFPFORK_DIRTY) &&
 
1027
                (gettimeofday(&tv, NULL) == 0)) {
 
1028
            ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
 
1029
                       tv.tv_sec);
 
1030
            doflush++;
 
1031
        }
 
1032
 
 
1033
        /*
 
1034
         * Only set the rfork's length if we're closing the rfork.
 
1035
         */
 
1036
        if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
 
1037
                ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
 
1038
            ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
 
1039
            doflush++;
 
1040
        }
 
1041
        if ( doflush ) {
 
1042
            ad_flush( ofork->of_ad, adflags );
 
1043
        }
 
1044
    }
 
1045
 
 
1046
    if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
 
1047
        LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
 
1048
        return( AFPERR_PARAM );
 
1049
    }
 
1050
 
 
1051
    of_dealloc( ofork );
 
1052
    return( AFP_OK );
 
1053
}
 
1054
 
 
1055
 
 
1056
static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
 
1057
                                     off_t offset, char *rbuf,
 
1058
                                     size_t rbuflen, const int xlate)
 
1059
{
 
1060
    char *p, *q;
 
1061
    ssize_t cc;
 
1062
 
 
1063
    /*
 
1064
     * If this file is of type TEXT, swap \015 to \012.
 
1065
     */
 
1066
    if (xlate) {
 
1067
        for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
 
1068
            if ( *p == '\015' ) {
 
1069
                *p = '\012';
 
1070
            } else if ( *p == '\012' ) {
 
1071
                *p = '\015';
 
1072
            }
 
1073
        }
 
1074
    }
 
1075
 
 
1076
    if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
 
1077
                        rbuf, rbuflen)) < 0 ) {
 
1078
        switch ( errno ) {
 
1079
        case EDQUOT :
 
1080
        case EFBIG :
 
1081
        case ENOSPC :
 
1082
            return( AFPERR_DFULL );
 
1083
        default :
 
1084
            LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
 
1085
            return( AFPERR_PARAM );
 
1086
        }
 
1087
    }
 
1088
 
 
1089
    return cc;
 
1090
}
 
1091
 
 
1092
/* FPWrite. NOTE: on an error, we always use afp_write_err as
 
1093
 * the client may have sent us a bunch of data that's not reflected 
 
1094
 * in reqcount et al. */
 
1095
int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
 
1096
AFPObj              *obj;
 
1097
char                *ibuf, *rbuf;
 
1098
int                 ibuflen, *rbuflen;
 
1099
{
 
1100
    struct ofork        *ofork;
 
1101
    int32_t             offset, saveoff, reqcount;
 
1102
    int                 endflag, eid, xlate = 0, err = AFP_OK;
 
1103
    u_int16_t           ofrefnum;
 
1104
    ssize_t             cc;
 
1105
 
 
1106
    /* figure out parameters */
 
1107
    ibuf++;
 
1108
    endflag = ENDBIT(*ibuf);
 
1109
    ibuf++;
 
1110
    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
1111
    ibuf += sizeof( ofrefnum );
 
1112
    memcpy(&offset, ibuf, sizeof( offset ));
 
1113
    offset = ntohl( offset );
 
1114
    ibuf += sizeof( offset );
 
1115
    memcpy(&reqcount, ibuf, sizeof( reqcount ));
 
1116
    reqcount = ntohl( reqcount );
 
1117
    ibuf += sizeof( reqcount );
 
1118
 
 
1119
    if (( ofork = of_find( ofrefnum )) == NULL ) {
 
1120
        LOG(log_error, logtype_afpd, "afp_write: of_find");
 
1121
        err = AFPERR_PARAM;
 
1122
        goto afp_write_err;
 
1123
    }
 
1124
 
 
1125
    if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
 
1126
        err = AFPERR_ACCESS;
 
1127
        goto afp_write_err;
 
1128
    }
 
1129
 
 
1130
#ifdef AFS
 
1131
    writtenfork = ofork;
 
1132
#endif /* AFS */
 
1133
 
 
1134
    if ( ofork->of_flags & AFPFORK_DATA) {
 
1135
        eid = ADEID_DFORK;
 
1136
        xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
 
1137
    } else if (ofork->of_flags & AFPFORK_RSRC) {
 
1138
        eid = ADEID_RFORK;
 
1139
    } else {
 
1140
        err = AFPERR_ACCESS; /* should never happen */
 
1141
        goto afp_write_err;
 
1142
    }
 
1143
 
 
1144
    if (endflag)
 
1145
        offset += ad_size(ofork->of_ad, eid);
 
1146
 
 
1147
    /* handle bogus parameters */
 
1148
    if (reqcount < 0 || offset < 0) {
 
1149
        err = AFPERR_PARAM;
 
1150
        goto afp_write_err;
 
1151
    }
 
1152
 
 
1153
    /* offset can overflow on 64-bit capable filesystems.
 
1154
     * report disk full if that's going to happen. */
 
1155
    if (offset + reqcount < 0) {
 
1156
        err = AFPERR_DFULL;
 
1157
        goto afp_write_err;
 
1158
    }
 
1159
 
 
1160
    if (!reqcount) { /* handle request counts of 0 */
 
1161
        err = AFP_OK;
 
1162
        offset = htonl(offset);
 
1163
        memcpy(rbuf, &offset, sizeof(offset));
 
1164
        goto afp_write_err;
 
1165
    }
 
1166
 
 
1167
    saveoff = offset;
 
1168
    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
 
1169
                   reqcount) < 0) {
 
1170
        err = AFPERR_LOCK;
 
1171
        goto afp_write_err;
 
1172
    }
 
1173
 
 
1174
    /* this is yucky, but dsi can stream i/o and asp can't */
 
1175
    switch (obj->proto) {
 
1176
#ifndef NO_DDP
 
1177
    case AFPPROTO_ASP:
 
1178
        if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
 
1179
            *rbuflen = 0;
 
1180
            LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
 
1181
            return( AFPERR_PARAM );
 
1182
        }
 
1183
 
 
1184
        if (obj->options.flags & OPTION_DEBUG) {
 
1185
            printf("(write) len: %d\n", *rbuflen);
 
1186
            bprint(rbuf, *rbuflen);
 
1187
        }
 
1188
 
 
1189
        if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
 
1190
                             xlate)) < 0) {
 
1191
            *rbuflen = 0;
 
1192
            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
 
1193
            return cc;
 
1194
        }
 
1195
        offset += cc;
 
1196
        break;
 
1197
#endif /* no afp/asp */
 
1198
 
 
1199
    case AFPPROTO_DSI:
 
1200
        {
 
1201
            DSI *dsi = obj->handle;
 
1202
 
 
1203
            /* find out what we have already and write it out. */
 
1204
            cc = dsi_writeinit(dsi, rbuf, *rbuflen);
 
1205
            if (!cc ||
 
1206
                    (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
 
1207
                dsi_writeflush(dsi);
 
1208
                *rbuflen = 0;
 
1209
                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
 
1210
                return cc;
 
1211
            }
 
1212
            offset += cc;
 
1213
 
 
1214
#if 0 /*def HAVE_SENDFILE_WRITE*/
 
1215
            if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
 
1216
                if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
 
1217
                                       offset, dsi->datasize)) < 0) {
 
1218
                    switch (errno) {
 
1219
                    case EDQUOT :
 
1220
                    case EFBIG :
 
1221
                    case ENOSPC :
 
1222
                        cc = AFPERR_DFULL;
 
1223
                        break;
 
1224
                    default :
 
1225
                        LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
 
1226
                        goto afp_write_loop;
 
1227
                    }
 
1228
                    dsi_writeflush(dsi);
 
1229
                    *rbuflen = 0;
 
1230
                    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
 
1231
                               reqcount);
 
1232
                    return cc;
 
1233
                }
 
1234
 
 
1235
                offset += cc;
 
1236
                goto afp_write_done;
 
1237
            }
 
1238
#endif /* 0, was HAVE_SENDFILE_WRITE */
 
1239
 
 
1240
            /* loop until everything gets written. currently
 
1241
                    * dsi_write handles the end case by itself. */
 
1242
            while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
 
1243
                if ( obj->options.flags & OPTION_DEBUG ) {
 
1244
                    printf("(write) command cont'd: %d\n", cc);
 
1245
                    bprint(rbuf, cc);
 
1246
                }
 
1247
 
 
1248
                if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
 
1249
                    dsi_writeflush(dsi);
 
1250
                    *rbuflen = 0;
 
1251
                    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
 
1252
                               reqcount);
 
1253
                    return cc;
 
1254
                }
 
1255
                offset += cc;
 
1256
            }
 
1257
        }
 
1258
        break;
 
1259
    }
 
1260
 
 
1261
    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
 
1262
    if ( ad_hfileno( ofork->of_ad ) != -1 )
 
1263
        ofork->of_flags |= AFPFORK_DIRTY;
 
1264
 
 
1265
    offset = htonl( offset );
 
1266
#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
 
1267
    bcopy(&offset, rbuf, sizeof(offset));
 
1268
#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
 
1269
    memcpy(rbuf, &offset, sizeof(offset));
 
1270
#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
 
1271
    *rbuflen = sizeof(offset);
 
1272
    return( AFP_OK );
 
1273
 
 
1274
afp_write_err:
 
1275
    if (obj->proto == AFPPROTO_DSI) {
 
1276
        dsi_writeinit(obj->handle, rbuf, *rbuflen);
 
1277
        dsi_writeflush(obj->handle);
 
1278
    }
 
1279
 
 
1280
    *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
 
1281
    return err;
 
1282
}
 
1283
 
 
1284
 
 
1285
int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
 
1286
AFPObj      *obj;
 
1287
char    *ibuf, *rbuf;
 
1288
int             ibuflen, *rbuflen;
 
1289
{
 
1290
    struct ofork        *ofork;
 
1291
    int                 buflen, ret;
 
1292
    u_int16_t           ofrefnum, bitmap;
 
1293
    u_int16_t           attrbits = 0;
 
1294
 
 
1295
    ibuf += 2;
 
1296
    memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
 
1297
    ibuf += sizeof( ofrefnum );
 
1298
    memcpy(&bitmap, ibuf, sizeof( bitmap ));
 
1299
    bitmap = ntohs( bitmap );
 
1300
    ibuf += sizeof( bitmap );
 
1301
 
 
1302
    *rbuflen = 0;
 
1303
    if (( ofork = of_find( ofrefnum )) == NULL ) {
 
1304
        LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
 
1305
        return( AFPERR_PARAM );
 
1306
    }
 
1307
    attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
 
1308
    attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
 
1309
 
 
1310
    if (( ret = getforkparams( ofork, bitmap,
 
1311
                               rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
 
1312
        return( ret );
 
1313
    }
 
1314
 
 
1315
    *rbuflen = buflen + sizeof( u_short );
 
1316
    bitmap = htons( bitmap );
 
1317
    memcpy(rbuf, &bitmap, sizeof( bitmap ));
 
1318
    return( AFP_OK );
 
1319
}
 
1320