X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Ffork.c;h=4c70cdbed7935ad3ee80e11606b63d34c43ce8b6;hp=0430e1a0d1d36b02909d4f37aa888e5a38284d12;hb=42a0a094b72577aee3fee7f186da52dc83db001d;hpb=62182ed80f098b859c8db943b4399f396048faa6 diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 0430e1a0..73abb1e9 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -1,7 +1,7 @@ /* - * $Id: fork.c,v 1.50 2003-03-09 19:55:35 didg Exp $ - * * Copyright (c) 1990,1993 Regents of The University of Michigan. + * Copyright (c) 2010 Frank Lahm + * * All Rights Reserved. See COPYRIGHT. */ @@ -10,110 +10,89 @@ #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 #include -#ifdef CNID_DB #include -#endif +#include +#include +#include +#include +#include #include "fork.h" #include "file.h" -#include "globals.h" #include "directory.h" #include "desktop.h" #include "volume.h" -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; -u_int16_t bitmap; -char *buf; -int *buflen; -const u_int16_t attrbits; +#ifdef AFS +struct ofork *writtenfork; +#endif + +static int getforkparams(const AFPObj *obj, struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen) { struct path path; - struct stat *st; + struct stat *st; + + struct adouble *adp; + struct dir *dir; + struct vol *vol; - 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 ( ad_hfileno( ofork->of_ad ) == -1 ) { + if (! AD_META_OPEN(ofork->of_ad)) { adp = NULL; } else { adp = ofork->of_ad; } vol = ofork->of_vol; - dir = ofork->of_dir; + dir = dirlookup(vol, ofork->of_did); - if (NULL == (path.u_name = mtoupath(vol, ofork->of_name, utf8_encoding()))) { + if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding(obj)))) { return( AFPERR_MISC ); } - path.m_name = ofork->of_name; + path.m_name = of_name(ofork); + path.id = 0; st = &path.st; - if ( bitmap & ( (1<of_ad ) == -1 ) { + if ( ad_data_fileno( ofork->of_ad ) <= 0 ) { + /* 0 is for symlink */ if (movecwd(vol, dir) < 0) return( AFPERR_NOOBJ ); - if ( stat( path.u_name, st ) < 0 ) + 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, attrbits ); + return getmetadata(obj, vol, bitmap, &path, dir, buf, buflen, adp ); } -/* ---------------------------- */ -static off_t get_off_t(ibuf, is64) -char **ibuf; -int is64; +static off_t get_off_t(char **ibuf, int is64) { - u_int32_t temp; + uint32_t temp; off_t ret; ret = 0; @@ -127,18 +106,14 @@ int is64; ret = ntohl(temp)| (ret << 32); } else { - ret = (int)ret; /* sign extend */ + ret = (int)ret; /* sign extend */ } return ret; } -/* ---------------------- */ -static int set_off_t(offset, rbuf, is64) -off_t offset; -char *rbuf; -int is64; +static int set_off_t(off_t offset, char *rbuf, int is64) { - u_int32_t temp; + uint32_t temp; int ret; ret = 0; @@ -156,37 +131,21 @@ int is64; return ret; } -/* ------------------------ -*/ static int is_neg(int is64, off_t val) { if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U))) - return 1; + return 1; return 0; } -static __inline__ int sum_neg(int is64, off_t offset, off_t reqcount) +static int sum_neg(int is64, off_t offset, off_t reqcount) { - if (is_neg(is64, offset +reqcount) ) - return 1; + 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); -} - -/* ------------------------- -*/ -static int getforkmode(struct adouble *adp, int eid, int what) -{ - return ad_testlock(adp, eid, what); -} - -static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum) +static int fork_setmode(const AFPObj *obj, struct adouble *adp, int eid, int access, int ofrefnum) { int ret; int readset; @@ -194,14 +153,35 @@ static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum) int denyreadset; int denywriteset; +#ifdef HAVE_FSHARE_T + fshare_t shmd; + + if (obj->options.flags & OPTION_SHARE_RESERV) { + shmd.f_access = (access & OPENACC_RD ? F_RDACC : 0) | (access & OPENACC_WR ? F_WRACC : 0); + if (shmd.f_access == 0) + /* we must give an access mode, otherwise fcntl will complain */ + shmd.f_access = F_RDACC; + shmd.f_deny = (access & OPENACC_DRD ? F_RDDNY : F_NODNY) | (access & OPENACC_DWR) ? F_WRDNY : 0; + shmd.f_id = ofrefnum; + + int fd = (eid == ADEID_DFORK) ? ad_data_fileno(adp) : ad_reso_fileno(adp); + + if (fd != -1 && fd != AD_SYMLINK && fcntl(fd, F_SHARE, &shmd) != 0) { + LOG(log_debug, logtype_afpd, "fork_setmode: fcntl: %s", strerror(errno)); + errno = EACCES; + return -1; + } + } +#endif + if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) { - return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE); + return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum); } if ((access & (OPENACC_RD | OPENACC_DRD))) { - if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0) + if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0) return readset; - if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0) + if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0) return denyreadset; if ((access & OPENACC_RD) && denyreadset) { @@ -211,26 +191,26 @@ static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum) if ((access & OPENACC_DRD) && readset) { errno = EACCES; return -1; - } + } /* boolean logic is not enough, because getforkmode is not always telling the - * true + * true */ if ((access & OPENACC_RD)) { - ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_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 = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD); + 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 = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0) + if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0) return writeset; - if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0) + if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0) return denywriteset; if ((access & OPENACC_WR) && denywriteset) { @@ -240,44 +220,38 @@ static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum) if ((access & OPENACC_DWR) && writeset) { errno = EACCES; return -1; - } + } if ((access & OPENACC_WR)) { - ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_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 = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR); + 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; } /* ----------------------- */ -int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +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; - 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; - + 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 )); @@ -292,7 +266,7 @@ int ibuflen, *rbuflen; ibuf += sizeof( int ); if (NULL == ( dir = dirlookup( vol, did ))) { - return afp_errno; + return afp_errno; } memcpy(&bitmap, ibuf, sizeof( bitmap )); @@ -307,12 +281,12 @@ int ibuflen, *rbuflen; } if (NULL == ( s_path = cname( vol, dir, &ibuf ))) { - return afp_errno; + return get_afp_errno(AFPERR_PARAM); } if (*s_path->m_name == '\0') { - /* it's a dir ! */ - return AFPERR_BADTYPE; + /* it's a dir ! */ + return AFPERR_BADTYPE; } /* stat() data fork st is set because it's not a dir */ @@ -324,164 +298,150 @@ int ibuflen, *rbuflen; case EACCES: return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS; default: - LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) ); + 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 (check_access(upath, access ) < 0) { - return AFPERR_ACCESS; + path = s_path->m_name; + st = &s_path->st; + + if (!vol_unix_priv(vol)) { + if (check_access(obj, vol, upath, access ) < 0) { + return AFPERR_ACCESS; + } + } else { + if (file_access(obj, vol, s_path, access ) < 0) { + return AFPERR_ACCESS; + } } - 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); - + if ((opened = of_findname(vol, s_path))) { adsame = opened->of_ad; } - if ( fork == OPENFORK_DATA ) { + adflags = ADFLAGS_SETSHRMD; + + if (fork == OPENFORK_DATA) { eid = ADEID_DFORK; - adflags = ADFLAGS_DF|ADFLAGS_HF; + adflags |= ADFLAGS_DF; } else { eid = ADEID_RFORK; - adflags = ADFLAGS_HF; + adflags |= ADFLAGS_RF; } - path = s_path->m_name; - if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, - adsame, st)) == NULL ) { - return( AFPERR_NFILE ); + if (access & OPENACC_WR) { + adflags |= ADFLAGS_RDWR; + if (fork != OPENFORK_DATA) + /* + * We only try to create the resource + * fork if the user wants to open it for write acess. + */ + adflags |= ADFLAGS_CREATE; + } else { + adflags |= ADFLAGS_RDONLY; } + if ((ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, adsame, st)) == NULL) + return AFPERR_NFILE; + + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)", + fullpathname(s_path->u_name), + (fork == OPENFORK_DATA) ? "data" : "reso", + !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR"); + 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; - } - 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: ad_open: %s", strerror(errno) ); - ret = AFPERR_PARAM; - goto openfork_err; - break; - } - } - else { - /* the ressource fork is open too */ - ofork->of_flags |= AFPFORK_OPEN; + + /* First ad_open(), opens data or ressource fork */ + if (ad_open(ofork->of_ad, upath, adflags, 0666) < 0) { + switch (errno) { + case EROFS: + ret = AFPERR_VLOCK; + case EACCES: + goto openfork_err; + case ENOENT: + goto openfork_err; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + ret = AFPERR_PARAM; + goto openfork_err; } + } + + /* + * Create metadata if we open rw, otherwise only open existing metadata + */ + if (access & OPENACC_WR) { + adflags = ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE; } 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; - } - /* 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: ad_open: %s", strerror(errno) ); + adflags = ADFLAGS_HF | ADFLAGS_RDONLY; + } + + if (ad_open(ofork->of_ad, upath, adflags, 0666) == 0) { + ofork->of_flags |= AFPFORK_META; + if (ad_get_MD_flags(ofork->of_ad) & O_CREAT) { + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): setting CNID", upath); + cnid_t id; + if ((id = get_id(vol, ofork->of_ad, st, dir->d_did, upath, strlen(upath))) == CNID_INVALID) { + LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): CNID error", upath); goto openfork_err; - break; } + (void)ad_setid(ofork->of_ad, st->st_dev, st->st_ino, id, dir->d_did, vol->v_stamp); + ad_flush(ofork->of_ad); } - else { - /* the ressource fork is open too */ - ofork->of_flags |= AFPFORK_OPEN; + } else { + switch (errno) { + case EACCES: + case ENOENT: + /* no metadata? We don't care! */ + break; + case EROFS: + ret = AFPERR_VLOCK; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + ret = AFPERR_PARAM; + goto openfork_err; } } - if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & 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 ); + 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 ); + } } - if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ), - &buflen, attrbits )) != AFP_OK ) { - ad_close( ofork->of_ad, adflags ); + if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) { + ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD); goto openfork_err; } - *rbuflen = buflen + 2 * sizeof( u_int16_t ); + *rbuflen = buflen + 2 * sizeof( uint16_t ); bitmap = htons( bitmap ); - memcpy(rbuf, &bitmap, sizeof( u_int16_t )); - rbuf += sizeof( u_int16_t ); + memcpy(rbuf, &bitmap, sizeof( uint16_t )); + rbuf += sizeof( uint16_t ); /* check WriteInhibit bit if we have a ressource fork - * the test is done here, after some Mac trafic capture + * the test is done here, after some Mac trafic capture */ - if (ad_hfileno(ofork->of_ad) != -1) { + 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 ); + ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD); + of_dealloc(ofork); ofrefnum = 0; memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); return(AFPERR_OLOCK); @@ -493,14 +453,16 @@ int ibuflen, *rbuflen; */ /* don't try to lock non-existent rforks. */ - if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) { - - ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum); + if ((eid == ADEID_DFORK) + || (ad_reso_fileno(ofork->of_ad) != -1) + || (ofork->of_ad->ad_vers == AD_VERSION_EA)) { + ret = fork_setmode(obj, ofork->of_ad, eid, access, ofrefnum); /* can we access the fork? */ if (ret < 0) { + ofork->of_flags |= AFPFORK_ERROR; ret = errno; - ad_close( ofork->of_ad, adflags ); - of_dealloc( ofork ); + ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD); + of_dealloc(ofork); switch (ret) { case EAGAIN: /* return data anyway */ case EACCES: @@ -511,7 +473,7 @@ int ibuflen, *rbuflen; break; default: *rbuflen = 0; - LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(ret) ); + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) ); return( AFPERR_PARAM ); } } @@ -522,29 +484,29 @@ int ibuflen, *rbuflen; if ((access & OPENACC_RD)) ofork->of_flags |= AFPFORK_ACCRD; + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): fork: %" PRIu16, + fullpathname(s_path->m_name), ofork->of_refnum); + memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); return( AFP_OK ); openfork_err: - of_dealloc( ofork ); + 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; +int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen) { - struct ofork *ofork; - off_t size; - u_int16_t ofrefnum, bitmap; + struct ofork *ofork; + off_t size; + uint16_t ofrefnum, bitmap; int err; int is64; int eid; - off_t st_size; - + off_t st_size; + ibuf += 2; memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); @@ -556,7 +518,7 @@ int ibuflen, *rbuflen; *rbuflen = 0; if (NULL == ( ofork = of_find( ofrefnum )) ) { - LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum ); + LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum ); return( AFPERR_PARAM ); } @@ -573,26 +535,26 @@ int ibuflen, *rbuflen; } else return AFPERR_PARAM; - if ( ( (bitmap & ( (1<= 30) { + if (obj->afp_version >= 30) { is64 = 4; } - else - return AFPERR_BITMAP; + else + return AFPERR_BITMAP; } if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4) return AFPERR_PARAM ; - + size = get_off_t(&ibuf, is64); if (size < 0) @@ -600,34 +562,35 @@ int ibuflen, *rbuflen; 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) + 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); + 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 ); + ad_refresh(NULL, 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) { + 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); + } + + err = ad_rtruncate(ofork->of_ad, mtoupath(ofork->of_vol, of_name(ofork), ofork->of_did, utf8_encoding(obj)), size); if (st_size > size) - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum); + 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, ADFLAGS_HF ) < 0) { - LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) ); + 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 @@ -635,7 +598,7 @@ int ibuflen, *rbuflen; #ifdef AFS if ( flushfork( ofork ) < 0 ) { - LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) ); + LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) ); } #endif /* AFS */ @@ -654,6 +617,7 @@ afp_setfork_err: case EDQUOT: case EFBIG: case ENOSPC: + LOG(log_error, logtype_afpd, "afp_setforkparams: DISK FULL"); return AFPERR_DFULL; default: return AFPERR_PARAM; @@ -665,26 +629,22 @@ afp_setfork_err: * 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. + * functions. */ #define ENDBIT(a) ((a) & 0x80) #define UNLOCKBIT(a) ((a) & 0x01) /* ---------------------- */ -static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; -int is64; +static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) { - struct ofork *ofork; + struct ofork *ofork; off_t offset, length; int eid; - u_int16_t ofrefnum; - u_int8_t flags; + uint16_t ofrefnum; + uint8_t flags; int lockop; - + *rbuflen = 0; /* figure out parameters */ @@ -695,7 +655,7 @@ int is64; ibuf += sizeof(ofrefnum); if (NULL == ( ofork = of_find( ofrefnum )) ) { - LOG(log_error, logtype_afpd, "afp_bytelock: of_find"); + LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum ); return( AFPERR_PARAM ); } @@ -709,18 +669,17 @@ int is64; 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))) { + 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; } if (ENDBIT(flags)) { offset += ad_size(ofork->of_ad, eid); - /* FIXME what do we do if file size > 2 GB and + /* FIXME what do we do if file size > 2 GB and it's not byte_lock_ext? */ } @@ -755,138 +714,64 @@ int is64; } /* --------------------------- */ -int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { - return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0); + 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; +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); + return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1); } #undef UNLOCKBIT -/* --------------------------- */ -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 (NULL == ( em = getextmap( of->of_name )) || - 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 ); - } - } -} - - -static __inline__ 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) +/*! + * Read *rbuflen bytes from fork at offset + * + * @param ofork (r) fork handle + * @param eid (r) data fork or ressource fork entry id + * @param offset (r) offset + * @param rbuf (r) data buffer + * @param rbuflen (rw) in: number of bytes to read, out: bytes read + * + * @return AFP status code + */ +static int read_file(const struct ofork *ofork, int eid, off_t offset, char *rbuf, size_t *rbuflen) { 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_afpd, "afp_read: ad_read: %s", strerror(errno) ); + 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; - } - } - - /* - * 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 ); - } + + if ((size_t)cc < *rbuflen) + 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, *rbuflen; -int is64; +static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64) { - struct ofork *ofork; - off_t size; - off_t offset, saveoff, reqcount, savereqcount; - int cc, err, eid, xlate = 0; - u_int16_t ofrefnum; - u_char nlmask, nlchar; - + DSI *dsi = obj->dsi; + struct ofork *ofork; + off_t offset, saveoff, reqcount, savereqcount, size; + ssize_t cc, err; + int eid; + uint16_t ofrefnum; + + /* we break the AFP spec here by not supporting nlmask and nlchar anymore */ + 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"); + LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum ); err = AFPERR_PARAM; goto afp_read_err; } @@ -895,27 +780,9 @@ int is64; 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 ( 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. */ @@ -923,111 +790,117 @@ int is64; goto afp_read_err; } + offset = get_off_t(&ibuf, is64); + reqcount = get_off_t(&ibuf, is64); + /* zero request count */ err = AFP_OK; if (!reqcount) { goto afp_read_err; } + AFP_READ_START((long)reqcount); + /* reqcount isn't always truthful. we need to deal with that. */ size = ad_size(ofork->of_ad, eid); + LOG(log_debug, logtype_afpd, + "afp_read(fork: %" PRIu16 " [%s], off: %" PRIu64 ", len: %" PRIu64 ", size: %" PRIu64 ")", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount, size); + if (offset >= size) { err = AFPERR_EOF; goto afp_read_err; } + /* subtract off the offset */ + if (reqcount + offset > size) { + reqcount = size - offset; + err = AFPERR_EOF; + } + savereqcount = reqcount; saveoff = offset; - if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) { - err = AFPERR_LOCK; + + if (reqcount < 0 || offset < 0) { + err = AFPERR_PARAM; 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; - - if (obj->options.flags & OPTION_DEBUG) { - printf( "(read) reply: %d/%d, %d\n", *rbuflen, - (int) reqcount, dsi->clientID); - bprint(rbuf, *rbuflen); + if (obj->options.flags & OPTION_AFP_READ_LOCK) { + if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) { + err = AFPERR_LOCK; + goto afp_read_err; } - /* subtract off the offset */ - size -= offset; - if (reqcount > size) { - reqcount = size; - err = AFPERR_EOF; - } - - 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) +#ifdef WITH_SENDFILE + if (!(eid == ADEID_DFORK && ad_data_fileno(ofork->of_ad) == AD_SYMLINK) && + !(obj->options.flags & OPTION_NOSENDFILE)) { + int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0); + if (dsi_stream_read_file(dsi, fd, offset, reqcount, err) < 0) { + LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", + of_name(ofork), strerror(errno)); goto afp_read_exit; + } + goto afp_read_done; + } +#endif - /* 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_afpd, "afp_read: ad_readfile: %s", strerror(errno)); - goto afp_read_exit; - } - } + *rbuflen = MIN(reqcount, dsi->server_quantum); - dsi_readdone(dsi); - goto afp_read_done; - } + cc = read_file(ofork, eid, offset, ibuf, rbuflen); + if (cc < 0) { + err = cc; + goto afp_read_done; + } -afp_read_loop: -#endif /* HAVE_SENDFILE_READ */ + LOG(log_debug, logtype_afpd, + "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file", + of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*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; - offset += *rbuflen; - if (obj->options.flags & OPTION_DEBUG) { - printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID); - bprint(rbuf, *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 ((cc = dsi_readinit(dsi, ibuf, *rbuflen, reqcount, err)) < 0) + goto afp_read_exit; + *rbuflen = cc; - /* 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; + while (*rbuflen > 0) { + /* + * This loop isn't really entered anymore, we've already + * sent the whole requested block in dsi_readinit(). + */ + cc = read_file(ofork, eid, offset, ibuf, rbuflen); + if (cc < 0) + goto afp_read_exit; -afp_read_exit: - LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno)); - dsi_readdone(dsi); - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum); - obj->exit(1); + offset += *rbuflen; + /* dsi_read() also returns buffer size of next allocation */ + cc = dsi_read(dsi, ibuf, *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); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + 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, savereqcount,ofork->of_refnum); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum); + + AFP_READ_DONE(); return err; afp_read_err: @@ -1036,31 +909,22 @@ afp_read_err: } /* ---------------------- */ -int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *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; +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); } /* ---------------------- */ -int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *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; + uint16_t vid; *rbuflen = 0; ibuf += 2; @@ -1074,50 +938,82 @@ int ibuflen, *rbuflen; return( AFP_OK ); } -int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +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; + struct ofork *ofork; + uint16_t ofrefnum; *rbuflen = 0; ibuf += 2; memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); if (NULL == ( ofork = of_find( ofrefnum )) ) { - LOG(log_error, logtype_afpd, "afp_flushfork: of_find"); + LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum ); return( AFPERR_PARAM ); } + LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)", + (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); + if ( flushfork( ofork ) < 0 ) { - LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) ); + LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) ); + } + + return( AFP_OK ); +} + +/* + 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; + uint16_t ofrefnum; + + *rbuflen = 0; + ibuf += 2; + + memcpy(&ofrefnum, ibuf, sizeof(ofrefnum)); + ibuf += sizeof( ofrefnum ); + + if (NULL == ( ofork = of_find( ofrefnum )) ) { + LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum ); + return( AFPERR_PARAM ); + } + + LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)", + (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); + + if ( flushfork( ofork ) < 0 ) { + LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) ); + return AFPERR_MISC; } return( AFP_OK ); } /* this is very similar to closefork */ -int flushfork( ofork ) -struct ofork *ofork; +int flushfork(struct ofork *ofork) { struct timeval tv; int err = 0, doflush = 0; - if ( ad_dfileno( ofork->of_ad ) != -1 && - fsync( ad_dfileno( ofork->of_ad )) < 0 ) { - LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s", - ad_dfileno(ofork->of_ad), strerror(errno) ); + 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; } - if ( ad_hfileno( ofork->of_ad ) != -1 && - (ofork->of_flags & AFPFORK_RSRC)) { + if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */ + (ofork->of_flags & AFPFORK_RSRC)) { /* read in the rfork length */ - ad_refresh(ofork->of_ad); + ad_refresh(NULL, ofork->of_ad); /* set the date if we're dirty */ if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) { @@ -1127,89 +1023,54 @@ struct ofork *ofork; } /* flush the header */ - if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0) - err = -1; + if (doflush && ad_flush(ofork->of_ad) < 0) + err = -1; - if (fsync( ad_hfileno( ofork->of_ad )) < 0) + if (fsync( ad_reso_fileno( ofork->of_ad )) < 0) err = -1; if (err < 0) - LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s", - ad_hfileno(ofork->of_ad), strerror(errno) ); + LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s", + of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) ); } return( err ); } -int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { - struct ofork *ofork; - struct timeval tv; - int adflags, doflush = 0; - u_int16_t ofrefnum; + struct ofork *ofork; + uint16_t ofrefnum; *rbuflen = 0; ibuf += 2; memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); if (NULL == ( ofork = of_find( ofrefnum )) ) { - LOG(log_error, logtype_afpd, "afp_closefork: of_find"); + 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 |= ADFLAGS_DF; - } - 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)) { - ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec); - doflush++; - } - if ( doflush ) { - ad_flush( ofork->of_ad, adflags ); - } - } - } + LOG(log_debug, logtype_afpd, "afp_closefork(fork: %" PRIu16 " [%s])", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "rsrc"); - if ( ad_close( ofork->of_ad, adflags ) < 0 ) { - LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) ); + if (of_closefork(obj, ofork) < 0 ) { + LOG(log_error, logtype_afpd, "afp_closefork: of_closefork: %s", strerror(errno) ); return( AFPERR_PARAM ); } - of_dealloc( ofork ); 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) +static ssize_t write_file(struct ofork *ofork, int eid, + off_t offset, char *rbuf, + size_t rbuflen) { - 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'; - } - } - } + LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)", + (uintmax_t)offset, rbuflen); if (( cc = ad_write(ofork->of_ad, eid, offset, 0, rbuf, rbuflen)) < 0 ) { @@ -1217,9 +1078,12 @@ static __inline__ ssize_t write_file(struct ofork *ofork, int eid, case EDQUOT : case EFBIG : case ENOSPC : + LOG(log_error, logtype_afpd, "write_file: DISK FULL"); return( AFPERR_DFULL ); + case EACCES: + return AFPERR_ACCESS; default : - LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) ); + LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) ); return( AFPERR_PARAM ); } } @@ -1228,20 +1092,21 @@ static __inline__ ssize_t write_file(struct ofork *ofork, int eid, } -/* 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, *rbuflen; -int is64; +/* + * 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; + struct ofork *ofork; + off_t offset, saveoff, reqcount, oldsize, newsize; + int endflag, eid, err = AFP_OK; + uint16_t ofrefnum; + ssize_t cc; + DSI *dsi = obj->dsi; + char *rcvbuf = (char *)dsi->commands; + size_t rcvbuflen = dsi->server_quantum; /* figure out parameters */ ibuf++; @@ -1254,11 +1119,14 @@ int is64; reqcount = get_off_t(&ibuf, is64); if (NULL == ( ofork = of_find( ofrefnum )) ) { - LOG(log_error, logtype_afpd, "afp_write: of_find"); + LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum ); err = AFPERR_PARAM; goto afp_write_err; } + LOG(log_debug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu64 ")", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount); + if ((ofork->of_flags & AFPFORK_ACCWR) == 0) { err = AFPERR_ACCESS; goto afp_write_err; @@ -1270,7 +1138,6 @@ int is64; 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 { @@ -1278,8 +1145,9 @@ int is64; goto afp_write_err; } + oldsize = ad_size(ofork->of_ad, eid); if (endflag) - offset += ad_size(ofork->of_ad, eid); + offset += oldsize; /* handle bogus parameters */ if (reqcount < 0 || offset < 0) { @@ -1287,9 +1155,12 @@ int is64; goto afp_write_err; } + newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize; + /* offset can overflow on 64-bit capable filesystems. * report disk full if that's going to happen. */ - if (sum_neg(is64, offset, reqcount)) { + if (sum_neg(is64, offset, reqcount)) { + LOG(log_error, logtype_afpd, "write_fork: DISK FULL"); err = AFPERR_DFULL; goto afp_write_err; } @@ -1300,148 +1171,130 @@ int is64; goto afp_write_err; } + AFP_WRITE_START((long)reqcount); + saveoff = offset; - if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, - reqcount, ofork->of_refnum) < 0) { - err = AFPERR_LOCK; - goto afp_write_err; + if (obj->options.flags & OPTION_AFP_READ_LOCK) { + 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) { + /* find out what we have already */ + if ((cc = dsi_writeinit(dsi, rcvbuf, rcvbuflen)) > 0) { + ssize_t written; + if ((written = write_file(ofork, eid, offset, rcvbuf, cc)) != cc) { + dsi_writeflush(dsi); *rbuflen = 0; - LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) ); - return( AFPERR_PARAM ); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); + if (written > 0) + /* It's used for the read size and as error code in write_file(), ugh */ + written = AFPERR_MISC; + return written; } + } - if (obj->options.flags & OPTION_DEBUG) { - printf("(write) len: %d\n", *rbuflen); - bprint(rbuf, *rbuflen); - } + offset += cc; + +#ifdef WITH_RECVFILE + if (obj->options.flags & OPTION_RECVFILE) { + LOG(log_maxdebug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu32 ")", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, dsi->datasize); - if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen, - xlate)) < 0) { + if ((cc = ad_recvfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize, obj->options.splice_size)) < dsi->datasize) { + switch (errno) { + case EDQUOT: + case EFBIG: + case ENOSPC: + cc = AFPERR_DFULL; + dsi_writeflush(dsi); + break; + case ENOSYS: + goto afp_write_loop; + default: + /* Low level error, can't do much to back up */ + cc = AFPERR_MISC; + LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno)); + } *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); return cc; } + offset += cc; - break; -#endif /* no afp/asp */ + goto afp_write_done; + } +#endif - case AFPPROTO_DSI: - { - DSI *dsi = obj->handle; +afp_write_loop: + /* loop until everything gets written. currently + * dsi_write handles the end case by itself. */ + while ((cc = dsi_write(dsi, rcvbuf, rcvbuflen))) { - /* 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 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, ofork->of_refnum); - return cc; - } - - 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. */ - 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, ofork->of_refnum); - return cc; - } - offset += cc; - } + if ((cc = write_file(ofork, eid, offset, rcvbuf, cc)) < 0) { + dsi_writeflush(dsi); + *rbuflen = 0; + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); + return cc; } - break; + + LOG(log_debug, logtype_afpd, "afp_write: wrote: %jd, offset: %jd", + (intmax_t)cc, (intmax_t)offset); + + offset += cc; } - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); - if ( ad_hfileno( ofork->of_ad ) != -1 ) +afp_write_done: + if (obj->options.flags & OPTION_AFP_READ_LOCK) + 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; + /* we have modified any fork, remember until close_fork */ + ofork->of_flags |= AFPFORK_MODIFIED; + + /* update write count */ + ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0; + *rbuflen = set_off_t (offset, rbuf, is64); + AFP_WRITE_DONE(); return( AFP_OK ); afp_write_err: - if (obj->proto == AFPPROTO_DSI) { - dsi_writeinit(obj->handle, rbuf, *rbuflen); - dsi_writeflush(obj->handle); - } + dsi_writeinit(dsi, rcvbuf, rcvbuflen); + dsi_writeflush(dsi); - *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0; + if (err != AFP_OK) { + *rbuflen = 0; + } return err; } /* ---------------------------- */ -int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *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; + */ +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); } /* ---------------------------- */ -int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) { - struct ofork *ofork; - int buflen, ret; - u_int16_t ofrefnum, bitmap; - u_int16_t attrbits = 0; - + struct ofork *ofork; + int ret; + uint16_t ofrefnum, bitmap; + size_t buflen; ibuf += 2; memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); ibuf += sizeof( ofrefnum ); @@ -1451,21 +1304,18 @@ int ibuflen, *rbuflen; *rbuflen = 0; if (NULL == ( ofork = of_find( ofrefnum )) ) { - LOG(log_error, logtype_afpd, "afp_getforkparams: of_find"); + 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 ( ad_hfileno( ofork->of_ad ) != -1 ) { - if ( ad_refresh( ofork->of_ad ) < 0 ) { - LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) ); + if (AD_META_OPEN(ofork->of_ad)) { + if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) { + LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) ); return( AFPERR_PARAM ); } } - if (AFP_OK != ( ret = getforkparams( ofork, bitmap, - rbuf + sizeof( u_short ), &buflen, attrbits ))) { + if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) { return( ret ); }