/*
- * $Id: fork.c,v 1.16 2002-01-17 16:19:06 jmarcus Exp $
- *
* Copyright (c) 1990,1993 Regents of The University of Michigan.
+ * Copyright (c) 2010 Frank Lahm
+ *
* All Rights Reserved. See COPYRIGHT.
*/
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#include <dirent.h>
#include <string.h>
#include <errno.h>
-#include <atalk/logger.h>
-
#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
#include <sys/socket.h>
+#include <inttypes.h>
-#include <netatalk/endian.h>
#include <netatalk/at.h>
-
#include <atalk/dsi.h>
-#include <atalk/atp.h>
-#include <atalk/asp.h>
#include <atalk/afp.h>
#include <atalk/adouble.h>
+#include <atalk/logger.h>
#include <atalk/util.h>
-#ifdef CNID_DB
#include <atalk/cnid.h>
-#endif
+#include <atalk/bstradd.h>
#include "fork.h"
#include "file.h"
#include "desktop.h"
#include "volume.h"
-#define BYTELOCK_MAX 0x7FFFFFFFU
-
-struct ofork *writtenfork;
+#ifdef AFS
+struct ofork *writtenfork;
+#endif
-static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
-struct ofork *ofork;
-u_int16_t bitmap;
-char *buf;
-int *buflen;
-const u_int16_t attrbits;
+static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
{
-#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;
-
- 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 path path;
+ struct stat *st;
+
+ struct adouble *adp;
+ struct dir *dir;
+ struct vol *vol;
+
/* can only get the length of the opened fork */
- if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
- ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
+ if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
+ && (ofork->of_flags & AFPFORK_RSRC))
+ ||
+ ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
+ && (ofork->of_flags & AFPFORK_DATA))) {
return( AFPERR_BITMAP );
}
- if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
- (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
- (1 << FILPBIT_BDATE))) {
- upath = mtoupath(ofork->of_vol, ofork->of_name);
- if ( ad_dfileno( ofork->of_ad ) == -1 ) {
- if ( stat( upath, &st ) < 0 )
+ if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
+ adp = NULL;
+ } else {
+ adp = ofork->of_ad;
+ }
+
+ vol = ofork->of_vol;
+ dir = dirlookup(vol, ofork->of_did);
+
+ if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
+ return( AFPERR_MISC );
+ }
+ path.m_name = of_name(ofork);
+ path.id = 0;
+ st = &path.st;
+ if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
+ (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
+ (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
+ if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
+ /* 0 is for symlink */
+ if (movecwd(vol, dir) < 0)
+ return( AFPERR_NOOBJ );
+ if ( lstat( path.u_name, st ) < 0 )
return( AFPERR_NOOBJ );
} else {
- if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
+ if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
return( AFPERR_BITMAP );
}
}
}
+ return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
+}
- 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;
-
- 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;
+static off_t get_off_t(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;
+}
- case FILPBIT_LNAME :
- nameoff = data;
- data += sizeof(u_int16_t);
- break;
+static int set_off_t(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_SNAME :
- memset(data, 0, sizeof(u_int16_t));
- data += sizeof(u_int16_t);
- break;
+ return ret;
+}
- 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 */
- }
+static int is_neg(int is64, off_t val)
+{
+ if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
+ return 1;
+ return 0;
+}
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- break;
+static int sum_neg(int is64, off_t offset, off_t reqcount)
+{
+ if (is_neg(is64, offset +reqcount) )
+ return 1;
+ return 0;
+}
- case FILPBIT_DFLEN :
- aint = htonl( st.st_size );
- 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 ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
+ }
- 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;
+ if ((access & (OPENACC_RD | OPENACC_DRD))) {
+ if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
+ return readset;
+ if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
+ return denyreadset;
- 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 = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
+ if (ret)
+ return ret;
+ }
+ if ((access & OPENACC_DRD)) {
+ ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
+ if (ret)
+ return ret;
+ }
+ }
+ /* ------------same for writing -------------- */
+ if ((access & (OPENACC_WR | OPENACC_DWR))) {
+ if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
+ return writeset;
+ if ((denywriteset = ad_testlock(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 = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
+ if (ret)
+ return ret;
+ }
+ if ((access & OPENACC_DWR)) {
+ ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
+ if (ret)
+ return ret;
}
+ }
+ if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
+ return ad_excl_lock(adp, eid);
+ }
+ return 0;
+}
- *buflen = data - buf;
- return( AFP_OK );
+/* ----------------------- */
+int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
+{
+ struct vol *vol;
+ struct dir *dir;
+ struct ofork *ofork, *opened;
+ struct adouble *adsame = NULL;
+ size_t buflen;
+ int ret, adflags, eid;
+ uint32_t did;
+ uint16_t vid, bitmap, access, ofrefnum;
+ char fork, *path, *upath;
+ struct stat *st;
+ uint16_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 );
}
- 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 );
+ LOG(log_debug, logtype_afpd,
+ "afp_openfork(\"%s\", %s)",
+ abspath(s_path->u_name),
+ (fork & OPENFORK_RSCS) ? "OPENFORK_RSCS" : "OPENFORK_DATA");
+
+ /* 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): %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))) {
+ 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;
+ if ( fork == OPENFORK_DATA ) {
+ eid = ADEID_DFORK;
+ adflags = ADFLAGS_DF | ADFLAGS_HF ;
+ } else {
+ eid = ADEID_RFORK;
+ adflags = ADFLAGS_RF | ADFLAGS_HF;
+ }
- 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;
+ 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(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 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(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 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(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 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(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 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(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 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\"): %s",
+ abspath(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_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
+ if (ad_setname(ofork->of_ad, path)) {
+ ad_flush( ofork->of_ad );
}
+ }
- *rbuflen = buflen + 2 * sizeof( u_int16_t );
- bitmap = htons( bitmap );
- memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
- rbuf += sizeof( u_int16_t );
-
- /*
- * 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.
- */
+ if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
+ ad_close( ofork->of_ad, adflags );
+ goto openfork_err;
+ }
- /* don't try to lock non-existent rforks. */
- if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
+ *rbuflen = buflen + 2 * sizeof( u_int16_t );
+ bitmap = htons( bitmap );
+ memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
+ rbuf += sizeof( u_int16_t );
- /* 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);
- }
+ /* check WriteInhibit bit if we have a ressource fork
+ * the test is done here, after some Mac trafic capture
+ */
+ if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
+ 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);
+ }
+ }
- 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);
- }
+ /*
+ * synchronization locks:
+ */
+
+ /* don't try to lock non-existent rforks. */
+ if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
- /* 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;
+ of_dealloc( ofork );
+ if (errno == EACCES)
+ return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
+ return ret;
+}
+
+int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *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 );
}
- 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 );
+ 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<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
+ && eid == ADEID_RFORK
+ ) ||
+ ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
+ && eid == ADEID_DFORK)) {
+ return AFPERR_BITMAP;
+ }
- *rbuflen = 0;
- if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_setforkparams: of_find: %s", strerror(errno) );
- return( AFPERR_PARAM );
+ is64 = 0;
+ if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
+ if (afp_version >= 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 ;
- if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
- return AFPERR_ACCESS;
+ size = get_off_t(&ibuf, is64);
- if (size < 0)
- return AFPERR_PARAM;
+ if (size < 0)
+ return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
- if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
- err = ad_dtruncate( ofork->of_ad, size );
- if (err < 0)
- goto afp_setfork_err;
- } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
- (ofork->of_flags & AFPFORK_RSRC)) {
- ad_refresh( ofork->of_ad );
- err = ad_rtruncate(ofork->of_ad, size);
- if (err < 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;
-#ifdef AFS
- if ( flushfork( ofork ) < 0 ) {
- LOG(log_error, logtype_default, "afp_setforkparams: flushfork: %s", strerror(errno) );
+ if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
+ 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_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<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
+ ad_refresh( ofork->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;
+
+ if (ad_flush( ofork->of_ad ) < 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;
+/* ---------------------- */
+static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *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 );
+ }
- memcpy(&offset, ibuf, sizeof( offset ));
- offset = ntohl(offset);
- ibuf += sizeof(offset);
+ 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_reso_fileno(ofork->of_ad))) { /* HF ?*/
+ return AFPERR_LOCK;
+ }
- memcpy(&length, ibuf, sizeof( length ));
- length = ntohl(length);
- if (length == 0xFFFFFFFF)
- length = BYTELOCK_MAX;
- else if (length <= 0) {
+ 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;
- } else if ((length >= AD_FILELOCK_BASE) &&
- (ad_hfileno(ofork->of_ad) == -1))
- return AFPERR_LOCK;
-
- if (ENDBIT(flags))
- offset += ad_size(ofork->of_ad, eid);
+ break;
+ }
+ }
+ *rbuflen = set_off_t (offset, rbuf, is64);
+ return( AFP_OK );
+}
- if (offset < 0) /* error if we have a negative offset */
- return AFPERR_PARAM;
+/* --------------------------- */
+int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+ return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
+}
- /* 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;
- }
- }
+/* --------------------------- */
+int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+ return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
+}
- offset = htonl(offset);
- memcpy(rbuf, &offset, sizeof( offset ));
- *rbuflen = sizeof( offset );
- return( AFP_OK );
- }
#undef UNLOCKBIT
+/* --------------------------- */
+static int crlf(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) == 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 );
- }
+ if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
+ /* 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;
+
+ } 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,
+ size_t *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 ( (size_t)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;
- }
+ *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(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
+{
+ struct ofork *ofork;
+ off_t offset, saveoff, reqcount, savereqcount;
+ ssize_t cc, err;
+ int 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;
+ }
- if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
- err = AFPERR_ACCESS;
- goto afp_read_err;
- }
+ 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);
- memcpy(&offset, ibuf, sizeof( offset ));
- offset = ntohl( offset );
- ibuf += sizeof( offset );
- memcpy(&reqcount, ibuf, sizeof( reqcount ));
- reqcount = ntohl( reqcount );
- ibuf += sizeof( reqcount );
+ LOG(log_debug, logtype_afpd,
+ "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+ 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;
+ }
+
+#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;
/* reqcount isn't always truthful. we need to deal with that. */
- if ((size = ad_size(ofork->of_ad, eid)) == 0) {
+ size = ad_size(ofork->of_ad, eid);
+
+ /* subtract off the offset */
+ size -= offset;
+ if (reqcount > size) {
+ reqcount = size;
err = AFPERR_EOF;
- goto afp_read_err;
}
- saveoff = offset;
- if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
- err = AFPERR_LOCK;
- goto afp_read_err;
- }
+ offset += *rbuflen;
-#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_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 ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
+ goto afp_read_exit;
+ *rbuflen = cc;
+ /* 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 WITH_SENDFILE
+ if (!(xlate)) {
+ int fd;
+
+ fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
+ if (dsi_stream_read_file(dsi, fd, 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 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;
+ dsi_readdone(dsi);
+ goto afp_read_done;
+ }
- /* subtract off the offset */
- size -= offset;
- if (reqcount > size) {
- reqcount = size;
- err = AFPERR_EOF;
- }
+ afp_read_loop:
+#endif
- if (obj->options.flags & OPTION_DEBUG) {
- printf( "(read) reply: %d/%d, %d\n", *rbuflen,
- reqcount, dsi->clientID);
- bprint(rbuf, *rbuflen);
- }
+ /* 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;
-
- /* 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)
+ /* 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;
+
+ afp_read_exit:
+ 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);
+ }
- /* 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;
- }
- }
+afp_read_done:
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
+ return err;
- dsi_readdone(dsi);
- goto afp_read_done;
- }
+afp_read_err:
+ *rbuflen = 0;
+ return err;
+}
-afp_read_loop:
-#endif /* HAVE_SENDFILE_READ */
+/* ---------------------- */
+int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+ return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
- /* 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;
+/* ---------------------- */
+int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+ return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
- offset += *rbuflen;
- if (obj->options.flags & OPTION_DEBUG) {
- printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
- bprint(rbuf, *rbuflen);
- }
+/* ---------------------- */
+int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+{
+ struct vol *vol;
+ u_int16_t vid;
- /* 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 = 0;
+ ibuf += 2;
-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);
- }
+ memcpy(&vid, ibuf, sizeof(vid));
+ if (NULL == ( vol = getvolbyvid( vid )) ) {
+ return( AFPERR_PARAM );
+ }
-afp_read_done:
- ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
- return err;
+ of_flush(vol);
+ return( AFP_OK );
+}
-afp_read_err:
- *rbuflen = 0;
- return err;
- }
+int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+{
+ struct ofork *ofork;
+ u_int16_t ofrefnum;
- 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;
+ memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
- *rbuflen = 0;
- ibuf += 2;
+ if (NULL == ( ofork = of_find( ofrefnum )) ) {
+ LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
+ return( AFPERR_PARAM );
+ }
- memcpy(&vid, ibuf, sizeof(vid));
- if (( vol = getvolbyvid( vid )) == NULL ) {
- return( AFPERR_PARAM );
- }
+ LOG(log_debug, logtype_afpd,
+ "afp_flushfork(\"%s\", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath),
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
- of_flush(vol);
- return( AFP_OK );
+ if ( flushfork( ofork ) < 0 ) {
+ LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
}
- int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
- AFPObj *obj;
- char *ibuf, *rbuf;
- int ibuflen, *rbuflen;
- {
- struct ofork *ofork;
- u_int16_t ofrefnum;
+ return( AFP_OK );
+}
- *rbuflen = 0;
- ibuf += 2;
- memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+/*
+ FIXME
+ There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
+ fsync(2) on OSX is implemented differently than on other platforms.
+ see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
+*/
+int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *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;
- if ( flushfork( ofork ) < 0 ) {
- LOG(log_error, logtype_default, "afp_flushfork: %s", strerror(errno) );
- }
+ memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
+ ibuf += sizeof( ofrefnum );
- return( AFP_OK );
+ if (NULL == ( ofork = of_find( ofrefnum )) ) {
+ LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
+ return( AFPERR_PARAM );
}
- /* 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;
- }
+ LOG(log_debug, logtype_afpd,
+ "afp_syncfork(\"%s\", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath),
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
- if ( ad_hfileno( ofork->of_ad ) != -1 ) {
+ if ( flushfork( ofork ) < 0 ) {
+ LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
+ return AFPERR_MISC;
+ }
- /* read in the rfork length */
- len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
- ad_refresh(ofork->of_ad);
+ return( AFP_OK );
+}
- /* 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++;
- }
+/* this is very similar to closefork */
+int flushfork(struct ofork *ofork)
+{
+ struct timeval tv;
- /* 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++;
- }
+ int err = 0, doflush = 0;
+ if ( ad_data_fileno( ofork->of_ad ) != -1 &&
+ fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
+ LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
+ of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
+ err = -1;
+ }
- /* 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;
+ if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
+ (ofork->of_flags & AFPFORK_RSRC)) {
- if (fsync( ad_hfileno( ofork->of_ad )) < 0)
- err = -1;
+ /* read in the rfork length */
+ ad_refresh(ofork->of_ad);
- if (err < 0)
- LOG(log_error, logtype_default, "flushfork: hfile(%d) %s",
- ad_hfileno(ofork->of_ad), strerror(errno) );
+ /* 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++;
}
- return( err );
- }
-
- 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;
+ /* flush the header */
+ if (doflush && ad_flush(ofork->of_ad) < 0)
+ err = -1;
- *rbuflen = 0;
- ibuf += 2;
- memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
+ if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
+ err = -1;
- if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_closefork: of_find: %s", strerror(errno) );
- return( AFPERR_PARAM );
- }
+ if (err < 0)
+ LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
+ of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
+ }
- adflags = 0;
- if ((ofork->of_flags & AFPFORK_DATA) &&
- (ad_dfileno( ofork->of_ad ) != -1)) {
- adflags |= ADFLAGS_DF;
- }
+ return( err );
+}
- if ( ad_hfileno( ofork->of_ad ) != -1 ) {
- adflags |= ADFLAGS_HF;
+int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+{
+ struct ofork *ofork;
+ u_int16_t ofrefnum;
- aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
- 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++;
- }
+ *rbuflen = 0;
+ ibuf += 2;
+ memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
- /*
- * 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 ( doflush ) {
- ad_flush( ofork->of_ad, adflags );
- }
- }
+ if (NULL == ( ofork = of_find( ofrefnum )) ) {
+ LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
+ return( AFPERR_PARAM );
+ }
- if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
- LOG(log_error, logtype_default, "afp_closefork: ad_close: %s", strerror(errno) );
- return( AFPERR_PARAM );
- }
+ LOG(log_debug, logtype_afpd,
+ "afp_closefork(\"%s\", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath),
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
- of_dealloc( ofork );
- return( AFP_OK );
+ if ( of_closefork( ofork ) < 0 ) {
+ LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
+ return( AFPERR_PARAM );
}
+ return( AFP_OK );
+}
- 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 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';
}
}
+ }
- 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 (( cc = ad_write(ofork->of_ad, eid, offset, 0,
+ rbuf, rbuflen)) < 0 ) {
+ switch ( errno ) {
+ case EDQUOT :
+ case EFBIG :
+ case ENOSPC :
+ return( AFPERR_DFULL );
+ case EACCES:
+ return AFPERR_ACCESS;
+ default :
+ LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
+ return( AFPERR_PARAM );
}
+ }
+
+ return cc;
+}
- 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. */
+static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *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;
}
- /* 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;
- }
+ LOG(log_debug, logtype_afpd,
+ "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
- if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
- err = AFPERR_ACCESS;
- 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) {
-#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 );
- }
+ /* this is yucky, but dsi can stream i/o and asp can't */
+ switch (obj->proto) {
+ case AFPPROTO_DSI:
+ {
+ DSI *dsi = obj->handle;
- if (obj->options.flags & OPTION_DEBUG) {
- printf("(write) len: %d\n", *rbuflen);
- bprint(rbuf, *rbuflen);
- }
+ /* 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, ofork->of_refnum);
+ return cc;
+ }
+ offset += cc;
- if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
- 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;
- 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) {
- dsi_writeflush(dsi);
- *rbuflen = 0;
- ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
- 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))) {
+ 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;
}
- break;
+ offset += cc;
}
+ }
+ 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_meta_fileno( ofork->of_ad ) != -1 ) /* META */
+ 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);
}
+ if (err != AFP_OK) {
+ *rbuflen = 0;
+ }
+ return err;
+}
+/* ---------------------------- */
+int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+ return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
- 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;
+/* ----------------------------
+ * FIXME need to deal with SIGXFSZ signal
+ */
+int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+ return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
- ibuf += 2;
- memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
- ibuf += sizeof( ofrefnum );
- memcpy(&bitmap, ibuf, sizeof( bitmap ));
- bitmap = ntohs( bitmap );
- ibuf += sizeof( bitmap );
+/* ---------------------------- */
+int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
+{
+ struct ofork *ofork;
+ int ret;
+ u_int16_t ofrefnum, bitmap;
+ size_t buflen;
+ 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 );
+ }
- *rbuflen = 0;
- if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_getforkparams: of_find: %s", strerror(errno) );
+ if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
+ 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 );
}
+ }
- if (( ret = getforkparams( ofork, bitmap,
- rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
- return( ret );
- }
-
- *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 ))) {
+ return( ret );
}
+ *rbuflen = buflen + sizeof( u_short );
+ bitmap = htons( bitmap );
+ memcpy(rbuf, &bitmap, sizeof( bitmap ));
+ return( AFP_OK );
+}
+