X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Ffork.c;h=c537c03b6ff16ad7daa79dcfd44a4cd34968d317;hb=9d78f9b52ea18b442fc91c6a1e8d8b607f2f90e8;hp=227c575e16d56ae16a542b304b1d29499a8911fb;hpb=708f57b6cdd3671457c420b36522f64c14c89c7e;p=netatalk.git diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 227c575e..c537c03b 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -1,5 +1,5 @@ /* - * $Id: fork.c,v 1.16 2002-01-17 16:19:06 jmarcus Exp $ + * $Id: fork.c,v 1.51.2.2.2.10.2.6 2008-11-25 15:16:33 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -10,35 +10,26 @@ #endif /* HAVE_CONFIG_H */ #include -#ifdef HAVE_UNISTD_H -#include -#endif /* HAVE_UNISTD_H */ -#ifdef HAVE_FCNTL_H -#include -#endif /* HAVE_FCNTL_H */ + #include #include #include + +#include #include #include -#include -#include -#include #include -#include #include #include #include #include #include -#include + #include -#ifdef CNID_DB #include -#endif #include "fork.h" #include "file.h" @@ -47,9 +38,17 @@ #include "desktop.h" #include "volume.h" -#define BYTELOCK_MAX 0x7FFFFFFFU +#ifdef DEBUG1 +#define Debug(a) ((a)->options.flags & OPTION_DEBUG) +#else +#define Debug(a) (0) +#endif struct ofork *writtenfork; +extern int getmetadata(struct vol *vol, + u_int16_t bitmap, + struct path *path, struct dir *dir, char *buf, + int *buflen, struct adouble *adp, int attrbits ); static int getforkparams(ofork, bitmap, buf, buflen, attrbits ) struct ofork *ofork; @@ -58,1313 +57,1429 @@ char *buf; int *buflen; const u_int16_t attrbits; { -#ifndef USE_LASTDID - struct stat hst, lst, *lstp; -#else /* USE_LASTDID */ - struct stat hst; -#endif - struct stat st; - struct extmap *em; - char *data, *nameoff = NULL, *upath; - int bit = 0, isad = 1; - u_int32_t aint; - u_int16_t ashort; + struct path path; + struct stat *st; - if ( ad_hfileno( ofork->of_ad ) == -1 ) { - isad = 0; - } else { - aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK ); - if ( ad_refresh( ofork->of_ad ) < 0 ) { - LOG(log_error, logtype_default, "getforkparams: ad_refresh: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } - /* See afp_closefork() for why this is bad */ - ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint ); - } + struct adouble *adp; + struct dir *dir; + struct vol *vol; + /* can only get the length of the opened fork */ - if (((bitmap & (1<of_flags & AFPFORK_RSRC)) || - ((bitmap & (1<of_flags & AFPFORK_DATA))) { + if ( ( (bitmap & ((1<of_flags & AFPFORK_RSRC)) + || + ( (bitmap & ((1<of_flags & AFPFORK_DATA))) { return( AFPERR_BITMAP ); } - if ( bitmap & ( 1<of_vol, ofork->of_name); + if ( ad_hfileno( ofork->of_ad ) == -1 ) { + adp = NULL; + } else { + adp = ofork->of_ad; + } + + vol = ofork->of_vol; + dir = ofork->of_dir; + + if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) { + return( AFPERR_MISC ); + } + path.m_name = of_name(ofork); + st = &path.st; + if ( bitmap & ( (1<of_ad ) == -1 ) { - if ( stat( upath, &st ) < 0 ) + if (movecwd(vol, dir) < 0) + return( AFPERR_NOOBJ ); + if ( stat( path.u_name, st ) < 0 ) return( AFPERR_NOOBJ ); } else { - if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) { + if ( fstat( ad_dfileno( ofork->of_ad ), st ) < 0 ) { return( AFPERR_BITMAP ); } } } + return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp, attrbits ); +} - data = buf; - while ( bitmap != 0 ) { - while (( bitmap & 1 ) == 0 ) { - bitmap = bitmap>>1; - bit++; - } - - switch ( bit ) { - case FILPBIT_ATTR : - if ( isad ) { - ad_getattr(ofork->of_ad, &ashort); - } else { - ashort = 0; - } - if (attrbits) - ashort = htons(ntohs(ashort) | attrbits); - memcpy(data, &ashort, sizeof( ashort )); - data += sizeof( ashort ); - break; - - case FILPBIT_PDID : - memcpy(data, &ofork->of_dir->d_did, sizeof( aint )); - data += sizeof( aint ); - break; - - case FILPBIT_CDATE : - if (!isad || - (ad_getdate(ofork->of_ad, AD_DATE_CREATE, &aint) < 0)) - aint = AD_DATE_FROM_UNIX(st.st_mtime); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; - - case FILPBIT_MDATE : - if (!isad || - (ad_getdate(ofork->of_ad, AD_DATE_MODIFY, &aint) < 0) || - (AD_DATE_TO_UNIX(aint) < st.st_mtime)) - aint = AD_DATE_FROM_UNIX(st.st_mtime); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; - - case FILPBIT_BDATE : - if (!isad || - (ad_getdate(ofork->of_ad, AD_DATE_BACKUP, &aint) < 0)) - aint = AD_DATE_START; - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; +/* ---------------------------- */ +static off_t get_off_t(ibuf, is64) +char **ibuf; +int is64; +{ + u_int32_t temp; + off_t ret; + + ret = 0; + memcpy(&temp, *ibuf, sizeof( temp )); + ret = ntohl(temp); /* ntohl is unsigned */ + *ibuf += sizeof(temp); + + if (is64) { + memcpy(&temp, *ibuf, sizeof( temp )); + *ibuf += sizeof(temp); + ret = ntohl(temp)| (ret << 32); + } + else { + ret = (int)ret; /* sign extend */ + } + return ret; +} + +/* ---------------------- */ +static int set_off_t(offset, rbuf, is64) +off_t offset; +char *rbuf; +int is64; +{ + u_int32_t temp; + int ret; + + ret = 0; + if (is64) { + temp = htonl(offset >> 32); + memcpy(rbuf, &temp, sizeof( temp )); + rbuf += sizeof(temp); + ret = sizeof( temp ); + offset &= 0xffffffff; + } + temp = htonl(offset); + memcpy(rbuf, &temp, sizeof( temp )); + ret += sizeof( temp ); - case FILPBIT_FINFO : - memcpy(data, isad ? - (void *) ad_entry(ofork->of_ad, ADEID_FINDERI) : - (void *) ufinderi, 32); - if ( !isad || - memcmp( ad_entry( ofork->of_ad, ADEID_FINDERI ), - ufinderi, 8 ) == 0 ) { - memcpy(data, ufinderi, 8 ); - if (( em = getextmap( ofork->of_name )) != NULL ) { - memcpy(data, em->em_type, sizeof( em->em_type )); - memcpy(data + 4, em->em_creator, - sizeof( em->em_creator )); - } - } - data += 32; - break; + return ret; +} - case FILPBIT_LNAME : - nameoff = data; - data += sizeof(u_int16_t); - break; +/* ------------------------ +*/ +static int is_neg(int is64, off_t val) +{ + if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U))) + return 1; + return 0; +} - case FILPBIT_SNAME : - memset(data, 0, sizeof(u_int16_t)); - data += sizeof(u_int16_t); - break; +static int sum_neg(int is64, off_t offset, off_t reqcount) +{ + if (is_neg(is64, offset +reqcount) ) + return 1; + return 0; +} + +/* ------------------------- +*/ +static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what) +{ + return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum); +} - case FILPBIT_FNUM : - aint = 0; -#if AD_VERSION > AD_VERSION1 - /* look in AD v2 header */ - if (isad) - memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint)); -#endif /* AD_VERSION > AD_VERSION1 */ - -#ifdef CNID_DB - aint = cnid_add(ofork->of_vol->v_db, &st, - ofork->of_dir->d_did, - upath, strlen(upath), aint); - if (aint > CNID_MAX) { - switch (aint) { - case CNID_ERR_PARAM: - LOG(log_error, logtype_default, "getforkparams: Incorrect parameters passed to cnid_add"); - return(AFPERR_PARAM); - case CNID_ERR_PATH: - return(AFPERR_PARAM); - case CNID_ERR_DB: - case CNID_ERR_MAX: - return(AFPERR_MISC); - } -#endif /* CNID_DB */ - - if (aint == 0) { -#ifdef USE_LASTDID - aint = htonl(( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff )); -#else /* USE_LASTDID */ - lstp = lstat(upath, &lst) < 0 ? st : &lst; -#ifdef DID_MTAB - aint = htonl( afpd_st_cnid ( lstp ) ); -#else /* DID_MTAB */ - aint = htonl(CNID(lstp, 1)); -#endif /* DID_MTAB */ -#endif /* USE_LASTDID */ - } +/* ------------------------- +*/ +int getforkmode(struct adouble *adp, int eid, int what) +{ + return ad_testlock(adp, eid, what); +} - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; +/* ------------------------- +*/ +static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum) +{ + int ret; + int readset; + int writeset; + int denyreadset; + int denywriteset; + + if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) { + return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE); + } - case FILPBIT_DFLEN : - aint = htonl( st.st_size ); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; + if ((access & (OPENACC_RD | OPENACC_DRD))) { + if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0) + return readset; + if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0) + return denyreadset; - case FILPBIT_RFLEN : - if ( isad ) { - aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK )); - } else { - aint = 0; - } - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; - - default : - return( AFPERR_BITMAP ); - } - bitmap = bitmap>>1; - bit++; + if ((access & OPENACC_RD) && denyreadset) { + errno = EACCES; + return -1; } - - if ( nameoff ) { - ashort = htons( data - buf ); - memcpy(nameoff, &ashort, sizeof( ashort )); - aint = strlen( ofork->of_name ); - aint = ( aint > MACFILELEN ) ? MACFILELEN : aint; - *data++ = aint; - memcpy(data, ofork->of_name, aint ); - data += aint; + if ((access & OPENACC_DRD) && readset) { + errno = EACCES; + return -1; + } + /* boolean logic is not enough, because getforkmode is not always telling the + * true + */ + if ((access & OPENACC_RD)) { + ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD); + if (ret) + return ret; + } + if ((access & OPENACC_DRD)) { + ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD); + if (ret) + return ret; + } + } + /* ------------same for writing -------------- */ + if ((access & (OPENACC_WR | OPENACC_DWR))) { + if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0) + return writeset; + if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0) + return denywriteset; + + if ((access & OPENACC_WR) && denywriteset) { + errno = EACCES; + return -1; + } + if ((access & OPENACC_DWR) && writeset) { + errno = EACCES; + return -1; + } + if ((access & OPENACC_WR)) { + ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR); + if (ret) + return ret; } + if ((access & OPENACC_DWR)) { + ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR); + if (ret) + return ret; + } + } + if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) { + return ad_excl_lock(adp, eid); + } + return 0; +} + +/* ----------------------- */ +int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj _U_; +char *ibuf, *rbuf; +int ibuflen _U_, *rbuflen; +{ + struct vol *vol; + struct dir *dir; + struct ofork *ofork, *opened; + struct adouble *adsame = NULL; + int buflen, ret, adflags, eid; + u_int32_t did; + u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0; + char fork, *path, *upath; + struct stat *st; + u_int16_t bshort; + struct path *s_path; + + ibuf++; + fork = *ibuf++; + memcpy(&vid, ibuf, sizeof( vid )); + ibuf += sizeof(vid); + + *rbuflen = 0; + if (NULL == ( vol = getvolbyvid( vid ))) { + return( AFPERR_PARAM ); + } - *buflen = data - buf; - return( AFP_OK ); - } - - int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct vol *vol; - struct dir *dir; - struct ofork *ofork, *opened; - struct adouble *adsame = NULL; - int buflen, ret, adflags, eid, lockop; - u_int32_t did; - u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0; - char fork, *path, *upath; - - ibuf++; - fork = *ibuf++; - memcpy(&vid, ibuf, sizeof( vid )); - ibuf += sizeof(vid); + memcpy(&did, ibuf, sizeof( did )); + ibuf += sizeof( int ); - *rbuflen = 0; - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM ); - } + if (NULL == ( dir = dirlookup( vol, did ))) { + return afp_errno; + } - memcpy(&did, ibuf, sizeof( did )); - ibuf += sizeof( int ); + memcpy(&bitmap, ibuf, sizeof( bitmap )); + bitmap = ntohs( bitmap ); + ibuf += sizeof( bitmap ); + memcpy(&access, ibuf, sizeof( access )); + access = ntohs( access ); + ibuf += sizeof( access ); - if (( dir = dirsearch( vol, did )) == NULL ) { - return( AFPERR_NOOBJ ); - } + if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) { + return AFPERR_VLOCK; + } - memcpy(&bitmap, ibuf, sizeof( bitmap )); - bitmap = ntohs( bitmap ); - ibuf += sizeof( bitmap ); - memcpy(&access, ibuf, sizeof( access )); - access = ntohs( access ); - ibuf += sizeof( access ); + if (NULL == ( s_path = cname( vol, dir, &ibuf ))) { + return get_afp_errno(AFPERR_PARAM); + } - if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) { - return AFPERR_VLOCK; - } + if (*s_path->m_name == '\0') { + /* it's a dir ! */ + return AFPERR_BADTYPE; + } - if (( path = cname( vol, dir, &ibuf )) == NULL ) { - return( AFPERR_NOOBJ ); + /* stat() data fork st is set because it's not a dir */ + switch ( s_path->st_errno ) { + case 0: + break; + case ENOENT: + return AFPERR_NOOBJ; + case EACCES: + return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + return AFPERR_PARAM; + } + /* FIXME should we check it first ? */ + upath = s_path->u_name; + if (!vol_unix_priv(vol)) { + if (check_access(upath, access ) < 0) { + return AFPERR_ACCESS; } - - if ( fork == OPENFORK_DATA ) { - eid = ADEID_DFORK; - adflags = ADFLAGS_DF|ADFLAGS_HF; - } else { - eid = ADEID_RFORK; - adflags = ADFLAGS_HF; + } + else { + if (file_access(s_path, access ) < 0) { + return AFPERR_ACCESS; } + } - /* XXX: this probably isn't the best way to do this. the already - open bits should really be set if the fork is opened by any - program, not just this one. however, that's problematic to do - if we can't write lock files somewhere. opened is also passed to - ad_open so that we can keep file locks together. */ - if ((opened = of_findname(vol, curdir, path))) { - attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) | - ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0); - adsame = opened->of_ad; - } + st = &s_path->st; + /* XXX: this probably isn't the best way to do this. the already + open bits should really be set if the fork is opened by any + program, not just this one. however, that's problematic to do + if we can't write lock files somewhere. opened is also passed to + ad_open so that we can keep file locks together. + FIXME: add the fork we are opening? + */ + if ((opened = of_findname(s_path))) { + attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0); + attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0); + + adsame = opened->of_ad; + } - if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, - adsame)) == NULL ) { - return( AFPERR_NFILE ); - } - if (access & OPENACC_WR) { - /* try opening in read-write mode */ - upath = mtoupath(vol, path); - ret = AFPERR_NOOBJ; - if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) { - switch ( errno ) { - case EROFS: - ret = AFPERR_VLOCK; - case EACCES: - goto openfork_err; - - break; - case ENOENT: - { - struct stat st; - - /* see if client asked for the data fork */ - if (fork == OPENFORK_DATA) { - if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) { - goto openfork_err; - } - adflags = ADFLAGS_DF; - - } else if (stat(upath, &st) == 0) { - /* here's the deal. we only try to create the resource - * fork if the user wants to open it for write acess. */ - if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0) - goto openfork_err; - } else - goto openfork_err; + if ( fork == OPENFORK_DATA ) { + eid = ADEID_DFORK; + adflags = ADFLAGS_DF|ADFLAGS_HF; + } else { + eid = ADEID_RFORK; + adflags = ADFLAGS_HF; + } + + path = s_path->m_name; + if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, + adsame, st)) == NULL ) { + return( AFPERR_NFILE ); + } + + ret = AFPERR_NOOBJ; + if (access & OPENACC_WR) { + /* try opening in read-write mode */ + if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) { + switch ( errno ) { + case EROFS: + ret = AFPERR_VLOCK; + case EACCES: + goto openfork_err; + break; + case ENOENT: + if (fork == OPENFORK_DATA) { + /* try to open only the data fork */ + if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) { + goto openfork_err; } - break; - case EMFILE : - case ENFILE : - ret = AFPERR_NFILE; - goto openfork_err; - break; - case EISDIR : - ret = AFPERR_BADTYPE; - goto openfork_err; - break; - default: - LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) ); - ret = AFPERR_PARAM; - goto openfork_err; - break; + adflags = ADFLAGS_DF; } + else { + /* here's the deal. we only try to create the resource + * fork if the user wants to open it for write acess. */ + if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0) + goto openfork_err; + ofork->of_flags |= AFPFORK_OPEN; + } + break; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + break; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + break; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + ret = AFPERR_PARAM; + goto openfork_err; + break; } - } else { - /* try opening in read-only mode */ - upath = mtoupath(vol, path); - ret = AFPERR_NOOBJ; - if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) { - switch ( errno ) { - case EROFS: - ret = AFPERR_VLOCK; - case EACCES: - /* check for a read-only data fork */ - if ((adflags != ADFLAGS_HF) && - (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0)) + } + else { + /* the ressource fork is open too */ + ofork->of_flags |= AFPFORK_OPEN; + } + } else { + /* try opening in read-only mode */ + ret = AFPERR_NOOBJ; + if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) { + switch ( errno ) { + case EROFS: + ret = AFPERR_VLOCK; + case EACCES: + goto openfork_err; + break; + case ENOENT: + /* see if client asked for a read only data fork */ + if (fork == OPENFORK_DATA) { + if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) { goto openfork_err; - - adflags = ADFLAGS_DF; - break; - case ENOENT: - { - struct stat st; - - /* see if client asked for the data fork */ - if (fork == OPENFORK_DATA) { - if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) { - goto openfork_err; - } - adflags = ADFLAGS_DF; - - } else if (stat(upath, &st) != 0) { - goto openfork_err; - } } - break; - case EMFILE : - case ENFILE : - ret = AFPERR_NFILE; - goto openfork_err; - break; - case EISDIR : - ret = AFPERR_BADTYPE; - goto openfork_err; - break; - default: - LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) ); - goto openfork_err; - break; + adflags = ADFLAGS_DF; } + /* else we don't set AFPFORK_OPEN because there's no ressource fork file + * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only + * then create in open read-write. + * FIXME , it doesn't play well with byte locking example: + * ressource fork open read only + * locking set on it (no effect, there's no file!) + * ressource fork open read write now + */ + break; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + break; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + break; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + goto openfork_err; + break; } } - - if ((adflags & ADFLAGS_HF) && - (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) { - ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path )); - memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path, - ad_getentrylen( ofork->of_ad, ADEID_NAME )); - ad_flush( ofork->of_ad, adflags ); + else { + /* the ressource fork is open too */ + ofork->of_flags |= AFPFORK_OPEN; } + } - if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ), - &buflen, attrbits )) != AFP_OK ) { - ad_close( ofork->of_ad, adflags ); - goto openfork_err; + if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) { + if (ad_setname(ofork->of_ad, path)) { + ad_flush( ofork->of_ad, adflags ); } + } - *rbuflen = buflen + 2 * sizeof( u_int16_t ); - bitmap = htons( bitmap ); - memcpy(rbuf, &bitmap, sizeof( u_int16_t )); - rbuf += sizeof( u_int16_t ); + if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ), + &buflen, attrbits )) != AFP_OK ) { + ad_close( ofork->of_ad, adflags ); + goto openfork_err; + } - /* - * synchronization locks: - * - * here's the ritual: - * 1) attempt a read lock to see if we have read or write - * privileges. - * 2) if that succeeds, set a write lock to correspond to the - * deny mode requested. - * 3) whenever a file is read/written, locks get set which - * prevent conflicts. - */ + *rbuflen = buflen + 2 * sizeof( u_int16_t ); + bitmap = htons( bitmap ); + memcpy(rbuf, &bitmap, sizeof( u_int16_t )); + rbuf += sizeof( u_int16_t ); - /* don't try to lock non-existent rforks. */ - if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) { + /* check WriteInhibit bit if we have a ressource fork + * the test is done here, after some Mac trafic capture + */ + if (ad_hfileno(ofork->of_ad) != -1) { + ad_getattr(ofork->of_ad, &bshort); + if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) { + ad_close( ofork->of_ad, adflags ); + of_dealloc( ofork ); + ofrefnum = 0; + memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); + return(AFPERR_OLOCK); + } + } - /* try to see if we have access. */ - ret = 0; - if (access & OPENACC_WR) { - ofork->of_flags |= AFPFORK_ACCWR; - ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK, - AD_FILELOCK_WR, 1, ofrefnum); - } + /* + * synchronization locks: + */ - if (!ret && (access & OPENACC_RD)) { - ofork->of_flags |= AFPFORK_ACCRD; - ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK, - AD_FILELOCK_RD, 1, ofrefnum); - } + /* don't try to lock non-existent rforks. */ + if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) { - /* can we access the fork? */ - if (ret < 0) { - ad_close( ofork->of_ad, adflags ); - of_dealloc( ofork ); + ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum); + /* can we access the fork? */ + if (ret < 0) { + ret = errno; + ad_close( ofork->of_ad, adflags ); + of_dealloc( ofork ); + switch (ret) { + case EAGAIN: /* return data anyway */ + case EACCES: + case EINVAL: ofrefnum = 0; memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); - return (AFPERR_DENYCONF); - } - - /* now try to set the deny lock. if the fork is open for read or - * write, a read lock will already have been set. otherwise, we upgrade - * our lock to a write lock. - * - * NOTE: we can't write lock a read-only file. on those, we just - * make sure that we have a read lock set. that way, we at least prevent - * someone else from really setting a deny read/write on the file. */ - lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ? - ADLOCK_WR : ADLOCK_RD; - ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid, - lockop | ADLOCK_FILELOCK | - ADLOCK_UPGRADE, AD_FILELOCK_WR, 1, - ofrefnum) : 0; - if (!ret && (access & OPENACC_DRD)) - ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK | - ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum); - - if (ret < 0) { - ret = errno; - ad_close( ofork->of_ad, adflags ); - of_dealloc( ofork ); - switch (ret) { - case EAGAIN: /* return data anyway */ - case EACCES: - case EINVAL: - ofrefnum = 0; - memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); - return( AFPERR_DENYCONF ); - break; - default: - *rbuflen = 0; - LOG(log_error, logtype_default, "afp_openfork: ad_lock: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } + return( AFPERR_DENYCONF ); + break; + default: + *rbuflen = 0; + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) ); + return( AFPERR_PARAM ); } } + if ((access & OPENACC_WR)) + ofork->of_flags |= AFPFORK_ACCWR; + } + /* the file may be open read only without ressource fork */ + if ((access & OPENACC_RD)) + ofork->of_flags |= AFPFORK_ACCRD; - memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); - return( AFP_OK ); + memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); + return( AFP_OK ); openfork_err: - of_dealloc( ofork ); - if (errno == EACCES) - return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS; - return ret; - } - - int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct ofork *ofork; - int32_t size; - u_int16_t ofrefnum, bitmap; - int err; - - ibuf += 2; - memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); - ibuf += sizeof( ofrefnum ); - memcpy(&bitmap, ibuf, sizeof(bitmap)); - bitmap = ntohs(bitmap); - ibuf += sizeof( bitmap ); - memcpy(&size, ibuf, sizeof( size )); - size = ntohl( size ); + of_dealloc( ofork ); + if (errno == EACCES) + return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS; + return ret; +} + +int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen, *rbuflen; +{ + struct ofork *ofork; + off_t size; + u_int16_t ofrefnum, bitmap; + int err; + int is64; + int eid; + off_t st_size; + + ibuf += 2; + + memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); + ibuf += sizeof( ofrefnum ); + + memcpy(&bitmap, ibuf, sizeof(bitmap)); + bitmap = ntohs(bitmap); + ibuf += sizeof( bitmap ); + + *rbuflen = 0; + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum ); + return( AFPERR_PARAM ); + } - *rbuflen = 0; - if (( ofork = of_find( ofrefnum )) == NULL ) { - LOG(log_error, logtype_default, "afp_setforkparams: of_find: %s", strerror(errno) ); - return( AFPERR_PARAM ); + if (ofork->of_vol->v_flags & AFPVOL_RO) + return AFPERR_VLOCK; + + if ((ofork->of_flags & AFPFORK_ACCWR) == 0) + return AFPERR_ACCESS; + + if ( ofork->of_flags & AFPFORK_DATA) { + eid = ADEID_DFORK; + } else if (ofork->of_flags & AFPFORK_RSRC) { + eid = ADEID_RFORK; + } else + return AFPERR_PARAM; + + if ( ( (bitmap & ( (1<= 30) { + is64 = 4; } + else + return AFPERR_BITMAP; + } - if (ofork->of_vol->v_flags & AFPVOL_RO) - return AFPERR_VLOCK; + if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4) + return AFPERR_PARAM ; + + size = get_off_t(&ibuf, is64); - if ((ofork->of_flags & AFPFORK_ACCWR) == 0) - return AFPERR_ACCESS; + if (size < 0) + return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */ - if (size < 0) - return AFPERR_PARAM; - if ((bitmap == (1<of_flags & AFPFORK_DATA)) { - err = ad_dtruncate( ofork->of_ad, size ); - if (err < 0) - goto afp_setfork_err; - } else if ((bitmap == (1<of_flags & AFPFORK_RSRC)) { - ad_refresh( ofork->of_ad ); - err = ad_rtruncate(ofork->of_ad, size); - if (err < 0) - goto afp_setfork_err; + if (bitmap == (1<of_ad, eid); + err = -2; + if (st_size > size && + ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) + goto afp_setfork_err; - if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) { - LOG(log_error, logtype_default, "afp_setforkparams: ad_flush: %s", - strerror(errno) ); - return( AFPERR_PARAM ); - } - } else - return AFPERR_BITMAP; + err = ad_dtruncate( ofork->of_ad, size ); + if (st_size > size) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum); + if (err < 0) + goto afp_setfork_err; + } else if (bitmap == (1<of_ad ); + + st_size = ad_size(ofork->of_ad, eid); + err = -2; + if (st_size > size && + ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) { + goto afp_setfork_err; + } + err = ad_rtruncate(ofork->of_ad, size); + if (st_size > size) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum); + if (err < 0) + goto afp_setfork_err; -#ifdef AFS - if ( flushfork( ofork ) < 0 ) { - LOG(log_error, logtype_default, "afp_setforkparams: flushfork: %s", strerror(errno) ); + if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) { + LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) ); + return AFPERR_PARAM; } + } else + return AFPERR_BITMAP; + +#ifdef AFS + if ( flushfork( ofork ) < 0 ) { + LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) ); + } #endif /* AFS */ - return( AFP_OK ); + return( AFP_OK ); afp_setfork_err: - if (err == -2) - return AFPERR_LOCK; - else { - switch (errno) { - case EROFS: - return AFPERR_VLOCK; - case EPERM: - case EACCES: - return AFPERR_ACCESS; - case EDQUOT: - case EFBIG: - case ENOSPC: - return AFPERR_DFULL; - default: - return AFPERR_PARAM; - } + if (err == -2) + return AFPERR_LOCK; + else { + switch (errno) { + case EROFS: + return AFPERR_VLOCK; + case EPERM: + case EACCES: + return AFPERR_ACCESS; + case EDQUOT: + case EFBIG: + case ENOSPC: + return AFPERR_DFULL; + default: + return AFPERR_PARAM; } } +} - /* for this to work correctly, we need to check for locks before each - * read and write. that's most easily handled by always doing an - * appropriate check before each ad_read/ad_write. other things - * that can change files like truncate are handled internally to those - * functions. - */ +/* for this to work correctly, we need to check for locks before each + * read and write. that's most easily handled by always doing an + * appropriate check before each ad_read/ad_write. other things + * that can change files like truncate are handled internally to those + * functions. + */ #define ENDBIT(a) ((a) & 0x80) #define UNLOCKBIT(a) ((a) & 0x01) - int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct ofork *ofork; - int32_t offset, length; - int eid; - u_int16_t ofrefnum; - u_int8_t flags; - - *rbuflen = 0; - - /* figure out parameters */ - ibuf++; - flags = *ibuf; /* first bit = endflag, lastbit = lockflag */ - ibuf++; - memcpy(&ofrefnum, ibuf, sizeof(ofrefnum)); - ibuf += sizeof(ofrefnum); - - if (( ofork = of_find( ofrefnum )) == NULL ) { - LOG(log_error, logtype_default, "afp_bytelock: of_find: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } - - if ( ofork->of_flags & AFPFORK_DATA) { - eid = ADEID_DFORK; - } else if (ofork->of_flags & AFPFORK_RSRC) { - eid = ADEID_RFORK; - } else - return AFPERR_PARAM; - memcpy(&offset, ibuf, sizeof( offset )); - offset = ntohl(offset); - ibuf += sizeof(offset); - memcpy(&length, ibuf, sizeof( length )); - length = ntohl(length); - if (length == 0xFFFFFFFF) - length = BYTELOCK_MAX; - else if (length <= 0) { - return AFPERR_PARAM; - } else if ((length >= AD_FILELOCK_BASE) && - (ad_hfileno(ofork->of_ad) == -1)) - return AFPERR_LOCK; +/* ---------------------- */ +static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 ) +AFPObj *obj _U_; +char *ibuf, *rbuf; +int ibuflen _U_, *rbuflen; +int is64; +{ + struct ofork *ofork; + off_t offset, length; + int eid; + u_int16_t ofrefnum; + u_int8_t flags; + int lockop; + + *rbuflen = 0; + + /* figure out parameters */ + ibuf++; + flags = *ibuf; /* first bit = endflag, lastbit = lockflag */ + ibuf++; + memcpy(&ofrefnum, ibuf, sizeof(ofrefnum)); + ibuf += sizeof(ofrefnum); + + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum ); + return( AFPERR_PARAM ); + } - if (ENDBIT(flags)) - offset += ad_size(ofork->of_ad, eid); + if ( ofork->of_flags & AFPFORK_DATA) { + eid = ADEID_DFORK; + } else if (ofork->of_flags & AFPFORK_RSRC) { + eid = ADEID_RFORK; + } else + return AFPERR_PARAM; + + offset = get_off_t(&ibuf, is64); + length = get_off_t(&ibuf, is64); + + /* FIXME AD_FILELOCK test is surely wrong */ + if (length == -1) + length = BYTELOCK_MAX; + else if (!length || is_neg(is64, length)) { + return AFPERR_PARAM; + } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) { + return AFPERR_LOCK; + } - if (offset < 0) /* error if we have a negative offset */ + if (ENDBIT(flags)) { + offset += ad_size(ofork->of_ad, eid); + /* FIXME what do we do if file size > 2 GB and + it's not byte_lock_ext? + */ + } + if (offset < 0) /* error if we have a negative offset */ + return AFPERR_PARAM; + + /* if the file is a read-only file, we use read locks instead of + * write locks. that way, we can prevent anyone from initiating + * a write lock. */ + lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR; + if (ad_lock(ofork->of_ad, eid, lockop, offset, length, + ofork->of_refnum) < 0) { + switch (errno) { + case EACCES: + case EAGAIN: + return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK; + break; + case ENOLCK: + return AFPERR_NLOCK; + break; + case EINVAL: + return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR; + break; + case EBADF: + default: return AFPERR_PARAM; - - /* if the file is a read-only file, we use read locks instead of - * write locks. that way, we can prevent anyone from initiating - * a write lock. */ - if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR : - ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ? - ADLOCK_WR : ADLOCK_RD), offset, length, - ofork->of_refnum) < 0) { - switch (errno) { - case EACCES: - case EAGAIN: - return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK; - break; - case ENOLCK: - return AFPERR_NLOCK; - break; - case EINVAL: - return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR; - break; - case EBADF: - default: - return AFPERR_PARAM; - break; - } + break; } - - offset = htonl(offset); - memcpy(rbuf, &offset, sizeof( offset )); - *rbuflen = sizeof( offset ); - return( AFP_OK ); } + *rbuflen = set_off_t (offset, rbuf, is64); + return( AFP_OK ); +} + +/* --------------------------- */ +int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0); +} + +/* --------------------------- */ +int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1); +} + #undef UNLOCKBIT +/* --------------------------- */ +static int crlf( of ) +struct ofork *of; +{ + struct extmap *em; - static __inline__ int crlf( of ) - struct ofork *of; - { - struct extmap *em; + if ( ad_hfileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { + /* no resource fork or no finderinfo, use our files extension mapping */ + if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) { + return 0; + } + /* file type is TEXT */ + return 1; - if ( ad_hfileno( of->of_ad ) == -1 || - memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ), - 8) == 0 ) { - if (( em = getextmap( of->of_name )) == NULL || - memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) { - return( 1 ); - } else { - return( 0 ); - } - } else { - if ( memcmp( ufinderi, - ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) { - return( 1 ); - } else { - return( 0 ); - } - } + } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) { + return 1; } + return 0; +} - static __inline__ ssize_t read_file(struct ofork *ofork, int eid, - int offset, u_char nlmask, - u_char nlchar, char *rbuf, - int *rbuflen, const int xlate) - { - ssize_t cc; - int eof = 0; - char *p, *q; +static ssize_t read_file(struct ofork *ofork, int eid, + off_t offset, u_char nlmask, + u_char nlchar, char *rbuf, + int *rbuflen, const int xlate) +{ + ssize_t cc; + int eof = 0; + char *p, *q; - cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen); - if ( cc < 0 ) { - LOG(log_error, logtype_default, "afp_read: ad_read: %s", strerror(errno) ); - *rbuflen = 0; - return( AFPERR_PARAM ); - } - if ( cc < *rbuflen ) { - eof = 1; - } + cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen); + if ( cc < 0 ) { + LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) ); + *rbuflen = 0; + return( AFPERR_PARAM ); + } + if ( cc < *rbuflen ) { + eof = 1; + } - /* - * Do Newline check. - */ - if ( nlmask != 0 ) { - for ( p = rbuf, q = p + cc; p < q; ) { - if (( *p++ & nlmask ) == nlchar ) { - break; - } - } - if ( p != q ) { - cc = p - rbuf; - eof = 0; + /* + * Do Newline check. + */ + if ( nlmask != 0 ) { + for ( p = rbuf, q = p + cc; p < q; ) { + if (( *p++ & nlmask ) == nlchar ) { + break; } } + if ( p != q ) { + cc = p - rbuf; + eof = 0; + } + } - /* - * If this file is of type TEXT, then swap \012 to \015. - */ - if (xlate) { - for ( p = rbuf, q = p + cc; p < q; p++ ) { - if ( *p == '\012' ) { - *p = '\015'; - } else if ( *p == '\015' ) { - *p = '\012'; - } - + /* + * If this file is of type TEXT, then swap \012 to \015. + */ + if (xlate) { + for ( p = rbuf, q = p + cc; p < q; p++ ) { + if ( *p == '\012' ) { + *p = '\015'; + } else if ( *p == '\015' ) { + *p = '\012'; } - } - *rbuflen = cc; - if ( eof ) { - return( AFPERR_EOF ); - } - return AFP_OK; - } - - int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct ofork *ofork; - off_t size; - int32_t offset, saveoff, reqcount; - int cc, err, eid, xlate = 0; - u_int16_t ofrefnum; - u_char nlmask, nlchar; - - ibuf += 2; - memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); - ibuf += sizeof( u_short ); - - if (( ofork = of_find( ofrefnum )) == NULL ) { - LOG(log_error, logtype_default, "afp_read: of_find: %s", strerror(errno) ); - err = AFPERR_PARAM; - goto afp_read_err; } + } - if ((ofork->of_flags & AFPFORK_ACCRD) == 0) { - err = AFPERR_ACCESS; - goto afp_read_err; - } + *rbuflen = cc; + if ( eof ) { + return( AFPERR_EOF ); + } + return AFP_OK; +} + +/* ----------------------------- + * with ddp, afp_read can return fewer bytes than in reqcount + * so return EOF only if read actually past end of file not + * if offset +reqcount > size of file + * e.g.: + * getfork size ==> 10430 + * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF) + * read fork offset 4264 size 6128 ==> 4264 (without EOF) + * read fork offset 9248 size 1508 ==> 1182 (EOF) + * 10752 is a bug in Mac 7.5.x finder + * + * with dsi, should we check that reqcount < server quantum? +*/ +static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen _U_, *rbuflen; +int is64; +{ + struct ofork *ofork; + off_t offset, saveoff, reqcount, savereqcount; + int cc, err, eid, xlate = 0; + u_int16_t ofrefnum; + u_char nlmask, nlchar; + + ibuf += 2; + memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); + ibuf += sizeof( u_short ); + + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum ); + err = AFPERR_PARAM; + goto afp_read_err; + } - memcpy(&offset, ibuf, sizeof( offset )); - offset = ntohl( offset ); - ibuf += sizeof( offset ); - memcpy(&reqcount, ibuf, sizeof( reqcount )); - reqcount = ntohl( reqcount ); - ibuf += sizeof( reqcount ); + if ((ofork->of_flags & AFPFORK_ACCRD) == 0) { + err = AFPERR_ACCESS; + goto afp_read_err; + } + offset = get_off_t(&ibuf, is64); + reqcount = get_off_t(&ibuf, is64); + if (is64) { + nlmask = nlchar = 0; + } + else { nlmask = *ibuf++; nlchar = *ibuf++; + } + /* if we wanted to be picky, we could add in the following + * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask)) + */ + if (reqcount < 0 || offset < 0) { + err = AFPERR_PARAM; + goto afp_read_err; + } - /* if we wanted to be picky, we could add in the following - * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask)) - */ - if (reqcount < 0 || offset < 0) { - err = AFPERR_PARAM; - goto afp_read_err; - } + if ( ofork->of_flags & AFPFORK_DATA) { + eid = ADEID_DFORK; + xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; + } else if (ofork->of_flags & AFPFORK_RSRC) { + eid = ADEID_RFORK; + } else { /* fork wasn't opened. this should never really happen. */ + err = AFPERR_ACCESS; + goto afp_read_err; + } - if ( ofork->of_flags & AFPFORK_DATA) { - eid = ADEID_DFORK; - xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; - } else if (ofork->of_flags & AFPFORK_RSRC) { - eid = ADEID_RFORK; - } else { /* fork wasn't opened. this should never really happen. */ - err = AFPERR_ACCESS; - goto afp_read_err; - } + /* zero request count */ + err = AFP_OK; + if (!reqcount) { + goto afp_read_err; + } - /* zero request count */ - if (!reqcount) { - err = AFP_OK; - goto afp_read_err; - } + savereqcount = reqcount; + saveoff = offset; + if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) { + err = AFPERR_LOCK; + goto afp_read_err; + } - /* reqcount isn't always truthful. we need to deal with that. */ - if ((size = ad_size(ofork->of_ad, eid)) == 0) { - err = AFPERR_EOF; - goto afp_read_err; +#define min(a,b) ((a)<(b)?(a):(b)) + *rbuflen = min( reqcount, *rbuflen ); + err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate); + if (err < 0) + goto afp_read_done; + + /* dsi can stream requests. we can only do this if we're not checking + * for an end-of-line character. oh well. */ + if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) { + DSI *dsi = obj->handle; + off_t size; + int non_blocking = 0; + +#ifdef DEBUG1 + if (obj->options.flags & OPTION_DEBUG) { + printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID); + bprint(rbuf, *rbuflen); } +#endif + /* reqcount isn't always truthful. we need to deal with that. */ + size = ad_size(ofork->of_ad, eid); - saveoff = offset; - if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) { - err = AFPERR_LOCK; - goto afp_read_err; + /* subtract off the offset */ + size -= offset; + if (reqcount > size) { + reqcount = size; + err = AFPERR_EOF; } -#define min(a,b) ((a)<(b)?(a):(b)) - *rbuflen = min( reqcount, *rbuflen ); - err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, - xlate); - if (err < 0) + offset += *rbuflen; + + /* dsi_readinit() returns size of next read buffer. by this point, + * we know that we're sending some data. if we fail, something + * horrible happened. */ + if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) + goto afp_read_exit; + + /* due to the nature of afp packets, we have to exit if we get + an error. we can't do this with translation on. */ +#if 0 /* ifdef WITH_SENDFILE */ + /* FIXME with OS X deadlock partial workaround we can't use sendfile */ + if (!(xlate || Debug(obj) )) { + if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize) < 0) { + if (errno == EINVAL || errno == ENOSYS) + goto afp_read_loop; + else { + LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno)); + goto afp_read_exit; + } + } + + dsi_readdone(dsi); goto afp_read_done; + } - /* dsi can stream requests. we can only do this if we're not checking - * for an end-of-line character. oh well. */ - if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) { - DSI *dsi = obj->handle; +afp_read_loop: +#endif - /* subtract off the offset */ - size -= offset; - if (reqcount > size) { - reqcount = size; - err = AFPERR_EOF; - } + /* fill up our buffer. */ + if (*rbuflen) { + /* set to non blocking mode */ + non_blocking = 1; + dsi_block(dsi, 1); + } + /* fill up our buffer. */ + while (*rbuflen > 0) { + cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate); + if (cc < 0) + goto afp_read_exit; + offset += *rbuflen; +#ifdef DEBUG1 if (obj->options.flags & OPTION_DEBUG) { - printf( "(read) reply: %d/%d, %d\n", *rbuflen, - reqcount, dsi->clientID); + printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID); bprint(rbuf, *rbuflen); } - - offset += *rbuflen; - - /* dsi_readinit() returns size of next read buffer. by this point, - * we know that we're sending some data. if we fail, something - * horrible happened. */ - if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) +#endif + /* dsi_read() also returns buffer size of next allocation */ + cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */ + if (cc < 0) goto afp_read_exit; - - /* due to the nature of afp packets, we have to exit if we get - an error. we can't do this with translation on. */ -#ifdef HAVE_SENDFILE_READ - if (!(xlate || (obj->options.flags & OPTION_DEBUG))) { - if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, - dsi->datasize) < 0) { - if (errno == EINVAL) - goto afp_read_loop; - else { - LOG(log_error, logtype_default, "afp_read: ad_readfile: %s", strerror(errno)); - goto afp_read_exit; - } - } - - dsi_readdone(dsi); - goto afp_read_done; - } - -afp_read_loop: -#endif /* HAVE_SENDFILE_READ */ - - /* fill up our buffer. */ - while (*rbuflen > 0) { - cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, - rbuflen, xlate); - if (cc < 0) - goto afp_read_exit; - - offset += *rbuflen; - if (obj->options.flags & OPTION_DEBUG) { - printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID); - bprint(rbuf, *rbuflen); - } - - /* dsi_read() also returns buffer size of next allocation */ - cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */ - if (cc < 0) - goto afp_read_exit; - *rbuflen = cc; - } - dsi_readdone(dsi); - goto afp_read_done; + *rbuflen = cc; + } + if (non_blocking) { + /* set back to blocking mode */ + dsi_block(dsi, 0); + } + dsi_readdone(dsi); + goto afp_read_done; afp_read_exit: - LOG(log_error, logtype_default, "afp_read: %s", strerror(errno)); - dsi_readdone(dsi); - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount); - obj->exit(1); - } + LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno)); + dsi_readdone(dsi); + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum); + obj->exit(EXITERR_CLNT); + } afp_read_done: - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount); - return err; + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum); + return err; afp_read_err: - *rbuflen = 0; - return err; - } - - int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct vol *vol; - u_int16_t vid; - - *rbuflen = 0; - ibuf += 2; + *rbuflen = 0; + return err; +} + +/* ---------------------- */ +int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0); +} + +/* ---------------------- */ +int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1); +} + +/* ---------------------- */ +int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen _U_, *rbuflen; +{ + struct vol *vol; + u_int16_t vid; - memcpy(&vid, ibuf, sizeof(vid)); - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM ); - } + *rbuflen = 0; + ibuf += 2; - of_flush(vol); - return( AFP_OK ); + memcpy(&vid, ibuf, sizeof(vid)); + if (NULL == ( vol = getvolbyvid( vid )) ) { + return( AFPERR_PARAM ); } - int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct ofork *ofork; - u_int16_t ofrefnum; + of_flush(vol); + return( AFP_OK ); +} - *rbuflen = 0; - ibuf += 2; - memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); +int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen _U_, *rbuflen; +{ + struct ofork *ofork; + u_int16_t ofrefnum; - if (( ofork = of_find( ofrefnum )) == NULL ) { - LOG(log_error, logtype_default, "afp_flushfork: of_find: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } + *rbuflen = 0; + ibuf += 2; + memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); - if ( flushfork( ofork ) < 0 ) { - LOG(log_error, logtype_default, "afp_flushfork: %s", strerror(errno) ); - } + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum ); + return( AFPERR_PARAM ); + } - return( AFP_OK ); + if ( flushfork( ofork ) < 0 ) { + LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) ); } - /* this is very similar to closefork */ - int flushfork( ofork ) - struct ofork *ofork; - { - struct timeval tv; - int len, err = 0, doflush = 0; - - if ( ad_dfileno( ofork->of_ad ) != -1 && - fsync( ad_dfileno( ofork->of_ad )) < 0 ) { - LOG(log_error, logtype_default, "flushfork: dfile(%d) %s", - ad_dfileno(ofork->of_ad), strerror(errno) ); - err = -1; - } + return( AFP_OK ); +} - if ( ad_hfileno( ofork->of_ad ) != -1 ) { +/* this is very similar to closefork */ +int flushfork( ofork ) +struct ofork *ofork; +{ + struct timeval tv; - /* read in the rfork length */ - len = ad_getentrylen(ofork->of_ad, ADEID_RFORK); - ad_refresh(ofork->of_ad); + int err = 0, doflush = 0; - /* set the date if we're dirty */ - if ((ofork->of_flags & AFPFORK_DIRTY) && - (gettimeofday(&tv, NULL) == 0)) { - ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec); - ofork->of_flags &= ~AFPFORK_DIRTY; - doflush++; - } + if ( ad_dfileno( ofork->of_ad ) != -1 && + fsync( ad_dfileno( ofork->of_ad )) < 0 ) { + LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s", + of_name(ofork), ad_dfileno(ofork->of_ad), strerror(errno) ); + err = -1; + } - /* if we're actually flushing this fork, make sure to set the - * length. otherwise, just use the stored length */ - if ((ofork->of_flags & AFPFORK_RSRC) && - (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) { - ad_setentrylen(ofork->of_ad, ADEID_RFORK, len); - doflush++; - } + if ( ad_hfileno( ofork->of_ad ) != -1 && + (ofork->of_flags & AFPFORK_RSRC)) { + /* read in the rfork length */ + ad_refresh(ofork->of_ad); - /* flush the header (if it is a resource fork) */ - if (ofork->of_flags & AFPFORK_RSRC) - if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)) - err = -1; + /* set the date if we're dirty */ + if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) { + ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec); + ofork->of_flags &= ~AFPFORK_DIRTY; + doflush++; + } - if (fsync( ad_hfileno( ofork->of_ad )) < 0) + /* flush the header */ + if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0) err = -1; - if (err < 0) - LOG(log_error, logtype_default, "flushfork: hfile(%d) %s", - ad_hfileno(ofork->of_ad), strerror(errno) ); - } + if (fsync( ad_hfileno( ofork->of_ad )) < 0) + err = -1; - return( err ); + if (err < 0) + LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s", + of_name(ofork), ad_hfileno(ofork->of_ad), strerror(errno) ); } - int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct ofork *ofork; - struct timeval tv; - int adflags, aint, doflush = 0; - u_int16_t ofrefnum; - - *rbuflen = 0; - ibuf += 2; - memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); + return( err ); +} - if (( ofork = of_find( ofrefnum )) == NULL ) { - LOG(log_error, logtype_default, "afp_closefork: of_find: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } +int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen _U_, *rbuflen; +{ + struct ofork *ofork; + struct timeval tv; + int adflags, doflush = 0; + u_int16_t ofrefnum; + int ret; + + + *rbuflen = 0; + ibuf += 2; + memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); + + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum ); + return( AFPERR_PARAM ); + } - adflags = 0; - if ((ofork->of_flags & AFPFORK_DATA) && - (ad_dfileno( ofork->of_ad ) != -1)) { + adflags = 0; + if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) { adflags |= ADFLAGS_DF; - } - - if ( ad_hfileno( ofork->of_ad ) != -1 ) { - adflags |= ADFLAGS_HF; - - aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK ); + } + if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) { + adflags |= ADFLAGS_HF; + /* + * Only set the rfork's length if we're closing the rfork. + */ + if ((ofork->of_flags & AFPFORK_RSRC)) { ad_refresh( ofork->of_ad ); - if ((ofork->of_flags & AFPFORK_DIRTY) && - (gettimeofday(&tv, NULL) == 0)) { - ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX, - tv.tv_sec); - doflush++; - } - - /* - * Only set the rfork's length if we're closing the rfork. - */ - if ((ofork->of_flags & AFPFORK_RSRC) && aint != - ad_getentrylen( ofork->of_ad, ADEID_RFORK )) { - ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint ); - doflush++; + if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) { + ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec); + doflush++; } if ( doflush ) { - ad_flush( ofork->of_ad, adflags ); + ad_flush( ofork->of_ad, adflags ); } } - - if ( ad_close( ofork->of_ad, adflags ) < 0 ) { - LOG(log_error, logtype_default, "afp_closefork: ad_close: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } - - of_dealloc( ofork ); - return( AFP_OK ); + } + ret = AFP_OK; + if ( ad_close( ofork->of_ad, adflags ) < 0 ) { + LOG(log_error, logtype_afpd, "afp_closefork(%s): ad_close: %s", of_name(ofork), strerror(errno) ); + ret = AFPERR_PARAM; } + of_dealloc( ofork ); + return ret; +} - static __inline__ ssize_t write_file(struct ofork *ofork, int eid, - off_t offset, char *rbuf, - size_t rbuflen, const int xlate) - { - char *p, *q; - ssize_t cc; - /* - * If this file is of type TEXT, swap \015 to \012. - */ - if (xlate) { - for ( p = rbuf, q = p + rbuflen; p < q; p++ ) { - if ( *p == '\015' ) { - *p = '\012'; - } else if ( *p == '\012' ) { - *p = '\015'; - } - } - } +static ssize_t write_file(struct ofork *ofork, int eid, + off_t offset, char *rbuf, + size_t rbuflen, const int xlate) +{ + char *p, *q; + ssize_t cc; - if (( cc = ad_write(ofork->of_ad, eid, offset, 0, - rbuf, rbuflen)) < 0 ) { - switch ( errno ) { - case EDQUOT : - case EFBIG : - case ENOSPC : - return( AFPERR_DFULL ); - default : - LOG(log_error, logtype_default, "afp_write: ad_write: %s", strerror(errno) ); - return( AFPERR_PARAM ); + /* + * If this file is of type TEXT, swap \015 to \012. + */ + if (xlate) { + for ( p = rbuf, q = p + rbuflen; p < q; p++ ) { + if ( *p == '\015' ) { + *p = '\012'; + } else if ( *p == '\012' ) { + *p = '\015'; } } + } - return cc; - } - - /* FPWrite. NOTE: on an error, we always use afp_write_err as - * the client may have sent us a bunch of data that's not reflected - * in reqcount et al. */ - int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct ofork *ofork; - int32_t offset, saveoff, reqcount; - int endflag, eid, xlate = 0, err = AFP_OK; - u_int16_t ofrefnum; - ssize_t cc; - - /* figure out parameters */ - ibuf++; - endflag = ENDBIT(*ibuf); - ibuf++; - memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); - ibuf += sizeof( ofrefnum ); - memcpy(&offset, ibuf, sizeof( offset )); - offset = ntohl( offset ); - ibuf += sizeof( offset ); - memcpy(&reqcount, ibuf, sizeof( reqcount )); - reqcount = ntohl( reqcount ); - ibuf += sizeof( reqcount ); - - if (( ofork = of_find( ofrefnum )) == NULL ) { - LOG(log_error, logtype_default, "afp_write: of_find: %s", strerror(errno) ); - err = AFPERR_PARAM; - goto afp_write_err; + if (( cc = ad_write(ofork->of_ad, eid, offset, 0, + rbuf, rbuflen)) < 0 ) { + switch ( errno ) { + case EDQUOT : + case EFBIG : + case ENOSPC : + return( AFPERR_DFULL ); + default : + LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) ); + return( AFPERR_PARAM ); } + } + + return cc; +} - if ((ofork->of_flags & AFPFORK_ACCWR) == 0) { - err = AFPERR_ACCESS; - goto afp_write_err; - } + +/* FPWrite. NOTE: on an error, we always use afp_write_err as + * the client may have sent us a bunch of data that's not reflected + * in reqcount et al. */ +static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen _U_, *rbuflen; +int is64; +{ + struct ofork *ofork; + off_t offset, saveoff, reqcount; + int endflag, eid, xlate = 0, err = AFP_OK; + u_int16_t ofrefnum; + ssize_t cc; + + /* figure out parameters */ + ibuf++; + endflag = ENDBIT(*ibuf); + ibuf++; + memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); + ibuf += sizeof( ofrefnum ); + + offset = get_off_t(&ibuf, is64); + reqcount = get_off_t(&ibuf, is64); + + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum ); + err = AFPERR_PARAM; + goto afp_write_err; + } + + if ((ofork->of_flags & AFPFORK_ACCWR) == 0) { + err = AFPERR_ACCESS; + goto afp_write_err; + } #ifdef AFS - writtenfork = ofork; + writtenfork = ofork; #endif /* AFS */ - if ( ofork->of_flags & AFPFORK_DATA) { - eid = ADEID_DFORK; - xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; - } else if (ofork->of_flags & AFPFORK_RSRC) { - eid = ADEID_RFORK; - } else { - err = AFPERR_ACCESS; /* should never happen */ - goto afp_write_err; - } + if ( ofork->of_flags & AFPFORK_DATA) { + eid = ADEID_DFORK; + xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0; + } else if (ofork->of_flags & AFPFORK_RSRC) { + eid = ADEID_RFORK; + } else { + err = AFPERR_ACCESS; /* should never happen */ + goto afp_write_err; + } - if (endflag) - offset += ad_size(ofork->of_ad, eid); + if (endflag) + offset += ad_size(ofork->of_ad, eid); - /* handle bogus parameters */ - if (reqcount < 0 || offset < 0) { - err = AFPERR_PARAM; - goto afp_write_err; - } + /* handle bogus parameters */ + if (reqcount < 0 || offset < 0) { + err = AFPERR_PARAM; + goto afp_write_err; + } - /* offset can overflow on 64-bit capable filesystems. - * report disk full if that's going to happen. */ - if (offset + reqcount < 0) { - err = AFPERR_DFULL; - goto afp_write_err; - } + /* offset can overflow on 64-bit capable filesystems. + * report disk full if that's going to happen. */ + if (sum_neg(is64, offset, reqcount)) { + err = AFPERR_DFULL; + goto afp_write_err; + } - if (!reqcount) { /* handle request counts of 0 */ - err = AFP_OK; - offset = htonl(offset); - memcpy(rbuf, &offset, sizeof(offset)); - goto afp_write_err; - } + if (!reqcount) { /* handle request counts of 0 */ + err = AFP_OK; + *rbuflen = set_off_t (offset, rbuf, is64); + goto afp_write_err; + } - saveoff = offset; - if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, - reqcount) < 0) { - err = AFPERR_LOCK; - goto afp_write_err; - } + saveoff = offset; + if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, + reqcount, ofork->of_refnum) < 0) { + err = AFPERR_LOCK; + goto afp_write_err; + } - /* this is yucky, but dsi can stream i/o and asp can't */ - switch (obj->proto) { + /* this is yucky, but dsi can stream i/o and asp can't */ + switch (obj->proto) { #ifndef NO_DDP - case AFPPROTO_ASP: - if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) { - *rbuflen = 0; - LOG(log_error, logtype_default, "afp_write: asp_wrtcont: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } + case AFPPROTO_ASP: + if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) { + *rbuflen = 0; + LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) ); + return( AFPERR_PARAM ); + } - if (obj->options.flags & OPTION_DEBUG) { - printf("(write) len: %d\n", *rbuflen); - bprint(rbuf, *rbuflen); - } +#ifdef DEBUG1 + if (obj->options.flags & OPTION_DEBUG) { + printf("(write) len: %d\n", *rbuflen); + bprint(rbuf, *rbuflen); + } +#endif + if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen, + xlate)) < 0) { + *rbuflen = 0; + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); + return cc; + } + offset += cc; + break; +#endif /* no afp/asp */ + + case AFPPROTO_DSI: + { + DSI *dsi = obj->handle; - if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen, - xlate)) < 0) { + /* find out what we have already and write it out. */ + cc = dsi_writeinit(dsi, rbuf, *rbuflen); + if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { + dsi_writeflush(dsi); *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount); + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); return cc; } offset += cc; - break; -#endif /* no afp/asp */ - case AFPPROTO_DSI: - { - DSI *dsi = obj->handle; - - /* find out what we have already and write it out. */ - cc = dsi_writeinit(dsi, rbuf, *rbuflen); - if (!cc || - (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { +#if 0 /*def HAVE_SENDFILE_WRITE*/ + if (!(xlate || obj->options.flags & OPTION_DEBUG)) { + if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket, + offset, dsi->datasize)) < 0) { + switch (errno) { + case EDQUOT : + case EFBIG : + case ENOSPC : + cc = AFPERR_DFULL; + break; + default : + LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) ); + goto afp_write_loop; + } dsi_writeflush(dsi); *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount); + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, + reqcount, ofork->of_refnum); return cc; } - offset += cc; - -#if 0 /*def HAVE_SENDFILE_WRITE*/ - if (!(xlate || obj->options.flags & OPTION_DEBUG)) { - if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket, - offset, dsi->datasize)) < 0) { - switch (errno) { - case EDQUOT : - case EFBIG : - case ENOSPC : - cc = AFPERR_DFULL; - break; - default : - LOG(log_error, logtype_default, "afp_write: ad_writefile: %s", strerror(errno) ); - goto afp_write_loop; - } - dsi_writeflush(dsi); - *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, - reqcount); - return cc; - } - offset += cc; - goto afp_write_done; - } + offset += cc; + goto afp_write_done; + } #endif /* 0, was HAVE_SENDFILE_WRITE */ - /* loop until everything gets written. currently - * dsi_write handles the end case by itself. */ -afp_write_loop: - while ((cc = dsi_write(dsi, rbuf, *rbuflen))) { - if ( obj->options.flags & OPTION_DEBUG ) { - printf("(write) command cont'd: %d\n", cc); - bprint(rbuf, cc); - } - - if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { - dsi_writeflush(dsi); - *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, - reqcount); - return cc; - } - offset += cc; + /* loop until everything gets written. currently + * dsi_write handles the end case by itself. */ + while ((cc = dsi_write(dsi, rbuf, *rbuflen))) { +#ifdef DEBUG1 + if ( obj->options.flags & OPTION_DEBUG ) { + printf("(write) command cont'd: %d\n", cc); + bprint(rbuf, cc); } +#endif + if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) { + dsi_writeflush(dsi); + *rbuflen = 0; + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, + reqcount, ofork->of_refnum); + return cc; + } + offset += cc; } - break; } + break; + } -afp_write_done: - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount); - if ( ad_hfileno( ofork->of_ad ) != -1 ) - ofork->of_flags |= AFPFORK_DIRTY; + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); + if ( ad_hfileno( ofork->of_ad ) != -1 ) + ofork->of_flags |= AFPFORK_DIRTY; - offset = htonl( offset ); -#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG) - bcopy(&offset, rbuf, sizeof(offset)); -#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */ - memcpy(rbuf, &offset, sizeof(offset)); -#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */ - *rbuflen = sizeof(offset); - return( AFP_OK ); + *rbuflen = set_off_t (offset, rbuf, is64); + return( AFP_OK ); afp_write_err: - if (obj->proto == AFPPROTO_DSI) { - dsi_writeinit(obj->handle, rbuf, *rbuflen); - dsi_writeflush(obj->handle); - } - - *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0; - return err; + if (obj->proto == AFPPROTO_DSI) { + dsi_writeinit(obj->handle, rbuf, *rbuflen); + dsi_writeflush(obj->handle); } - - - int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct ofork *ofork; - int buflen, ret; - u_int16_t ofrefnum, bitmap; - - ibuf += 2; - memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); - ibuf += sizeof( ofrefnum ); - memcpy(&bitmap, ibuf, sizeof( bitmap )); - bitmap = ntohs( bitmap ); - ibuf += sizeof( bitmap ); - + if (err != AFP_OK) { *rbuflen = 0; - if (( ofork = of_find( ofrefnum )) == NULL ) { - LOG(log_error, logtype_default, "afp_getforkparams: of_find: %s", strerror(errno) ); - return( AFPERR_PARAM ); - } + } + return err; +} + +/* ---------------------------- */ +int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0); +} + +/* ---------------------------- + * FIXME need to deal with SIGXFSZ signal +*/ +int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1); +} + +/* ---------------------------- */ +int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj _U_; +char *ibuf, *rbuf; +int ibuflen _U_, *rbuflen; +{ + struct ofork *ofork; + int buflen, ret; + u_int16_t ofrefnum, bitmap; + u_int16_t attrbits = 0; + + ibuf += 2; + memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); + ibuf += sizeof( ofrefnum ); + memcpy(&bitmap, ibuf, sizeof( bitmap )); + bitmap = ntohs( bitmap ); + ibuf += sizeof( bitmap ); + + *rbuflen = 0; + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum ); + return( AFPERR_PARAM ); + } + attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0); + attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0); - if (( ret = getforkparams( ofork, bitmap, - rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) { - return( ret ); + if ( ad_hfileno( ofork->of_ad ) != -1 ) { + if ( ad_refresh( ofork->of_ad ) < 0 ) { + LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) ); + return( AFPERR_PARAM ); } + } - *rbuflen = buflen + sizeof( u_short ); - bitmap = htons( bitmap ); - memcpy(rbuf, &bitmap, sizeof( bitmap )); - return( AFP_OK ); + if (AFP_OK != ( ret = getforkparams( ofork, bitmap, + rbuf + sizeof( u_short ), &buflen, attrbits ))) { + return( ret ); } + *rbuflen = buflen + sizeof( u_short ); + bitmap = htons( bitmap ); + memcpy(rbuf, &bitmap, sizeof( bitmap )); + return( AFP_OK ); +} +