X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Ffile.c;h=9f8ca89a74f8cbc27d0a4bc4934b0b1b2fdbd342;hb=2cd6217f54c7c93b4aee83d744755bf009680202;hp=826577bb5eb0707c33c60be8cc664046eff7bbd6;hpb=708f57b6cdd3671457c420b36522f64c14c89c7e;p=netatalk.git diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 826577bb..9f8ca89a 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,5 +1,5 @@ /* - * $Id: file.c,v 1.36 2002-01-17 16:19:06 jmarcus Exp $ + * $Id: file.c,v 1.62 2002-10-05 14:04:47 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -59,16 +59,6 @@ char *strchr (), *strrchr (); #include "filedir.h" #include "globals.h" -/* check for mtab DID code */ -#ifdef DID_MTAB -#include "parse_mtab.h" -#endif /* DID_MTAB */ - -#ifdef FORCE_UIDGID -#warning UIDGID -#include "uid.h" -#endif /* FORCE_UIDGID */ - /* the format for the finderinfo fields (from IM: Toolbox Essentials): * field bytes subfield bytes * @@ -89,48 +79,34 @@ char *strchr (), *strrchr (); */ const u_char ufinderi[] = { - 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X', - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; + 'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X', + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; -int getfilparams(struct vol *vol, +int getmetadata(struct vol *vol, u_int16_t bitmap, char *path, struct dir *dir, struct stat *st, - char *buf, int *buflen ) + char *buf, int *buflen, struct adouble *adp, int attrbits ) { #ifndef USE_LASTDID - struct stat hst, lst, *lstp; -#else /* USE_LASTDID */ - struct stat hst; + struct stat lst, *lstp; #endif /* USE_LASTDID */ - struct adouble ad, *adp; - struct ofork *of; + struct stat hst; struct extmap *em; char *data, *nameoff = NULL, *upath; - int bit = 0, isad = 1; + int bit = 0; u_int32_t aint; u_int16_t ashort; u_char achar, fdType[4]; + struct maccess ma; #ifdef DEBUG - LOG(log_info, logtype_default, "begin getfilparams:"); + LOG(log_info, logtype_afpd, "begin getmetadata:"); #endif /* DEBUG */ upath = mtoupath(vol, path); - if ((of = of_findname(vol, curdir, path))) { - adp = of->of_ad; - } else { - memset(&ad, 0, sizeof(ad)); - adp = &ad; - } - - if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) { - isad = 0; - } else if ( fstat( ad_hfileno( adp ), &hst ) < 0 ) { - LOG(log_error, logtype_default, "getfilparams fstat: %s", strerror(errno) ); - } data = buf; while ( bitmap != 0 ) { @@ -141,14 +117,27 @@ int getfilparams(struct vol *vol, switch ( bit ) { case FILPBIT_ATTR : - if ( isad ) { + if ( adp ) { ad_getattr(adp, &ashort); } else if (*upath == '.') { ashort = htons(ATTRBIT_INVISIBLE); } else ashort = 0; +#if 0 + /* FIXME do we want a visual clue if the file is read only + */ + accessmode( ".", &ma, dir , NULL); + if ((ma.ma_user & AR_UWRITE)) { + accessmode( upath, &ma, dir , st); + if (!(ma.ma_user & AR_UWRITE)) { + attrbits |= ATTRBIT_NOWRITE; + } + } +#endif + if (attrbits) + ashort = htons(ntohs(ashort) | attrbits); memcpy(data, &ashort, sizeof( ashort )); - data += sizeof( u_short ); + data += sizeof( ashort ); break; case FILPBIT_PDID : @@ -157,17 +146,16 @@ int getfilparams(struct vol *vol, break; case FILPBIT_CDATE : - if (!isad || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0)) + if (!adp || (ad_getdate(adp, 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(adp, AD_DATE_MODIFY, &aint) == 0)) { - if ((st->st_mtime > AD_DATE_TO_UNIX(aint)) && - (hst.st_mtime < st->st_mtime)) { - aint = AD_DATE_FROM_UNIX(st->st_mtime); + if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) { + if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) { + aint = AD_DATE_FROM_UNIX(st->st_mtime); } } else { aint = AD_DATE_FROM_UNIX(st->st_mtime); @@ -177,14 +165,14 @@ int getfilparams(struct vol *vol, break; case FILPBIT_BDATE : - if (!isad || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0)) + if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0)) aint = AD_DATE_START; memcpy(data, &aint, sizeof( int )); data += sizeof( int ); break; case FILPBIT_FINFO : - if (isad) + if (adp) memcpy(data, ad_entry(adp, ADEID_FINDERI), 32); else { memcpy(data, ufinderi, 32); @@ -194,9 +182,9 @@ int getfilparams(struct vol *vol, } } - if ((!isad || (memcmp(ad_entry(adp, ADEID_FINDERI), - ufinderi, 8 ) == 0)) && - (em = getextmap( path ))) { + if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 )) + && (em = getextmap( path )) + ) { memcpy(data, em->em_type, sizeof( em->em_type )); memcpy(data + 4, em->em_creator, sizeof(em->em_creator)); } @@ -217,7 +205,7 @@ int getfilparams(struct vol *vol, aint = 0; #if AD_VERSION > AD_VERSION1 /* look in AD v2 header */ - if (isad) + if (adp) memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint)); #endif /* AD_VERSION > AD_VERSION1 */ @@ -225,10 +213,10 @@ int getfilparams(struct vol *vol, aint = cnid_add(vol->v_db, st, dir->d_did, upath, strlen(upath), aint); /* Throw errors if cnid_add fails. */ - if (aint > CNID_MAX) { - switch (aint) { + if (aint == CNID_INVALID) { + switch (errno) { case CNID_ERR_PARAM: - LOG(log_error, logtype_default, "getfilparams: Incorrect parameters passed to cnid_add"); + LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add"); return(AFPERR_PARAM); case CNID_ERR_PATH: return(AFPERR_PARAM); @@ -236,1509 +224,1619 @@ int getfilparams(struct vol *vol, case CNID_ERR_MAX: return(AFPERR_MISC); } + } #endif /* CNID_DB */ - if (aint == 0) { - /* - * What a fucking mess. First thing: DID and FNUMs are - * in the same space for purposes of enumerate (and several - * other wierd places). While we consider this Apple's bug, - * this is the work-around: In order to maintain constant and - * unique DIDs and FNUMs, we monotonically generate the DIDs - * during the session, and derive the FNUMs from the filesystem. - * Since the DIDs are small, we insure that the FNUMs are fairly - * large by setting thier high bits to the device number. - * - * AFS already does something very similar to this for the - * inode number, so we don't repeat the procedure. - * - * new algorithm: - * due to complaints over did's being non-persistent, - * here's the current hack to provide semi-persistent - * did's: - * 1) we reserve the first bit for file ids. - * 2) the next 7 bits are for the device. - * 3) the remaining 24 bits are for the inode. - * - * both the inode and device information are actually hashes - * that are then truncated to the requisite bit length. - * - * it should be okay to use lstat to deal with symlinks. - */ + if (aint == 0) { + /* + * What a fucking mess. First thing: DID and FNUMs are + * in the same space for purposes of enumerate (and several + * other wierd places). While we consider this Apple's bug, + * this is the work-around: In order to maintain constant and + * unique DIDs and FNUMs, we monotonically generate the DIDs + * during the session, and derive the FNUMs from the filesystem. + * Since the DIDs are small, we insure that the FNUMs are fairly + * large by setting thier high bits to the device number. + * + * AFS already does something very similar to this for the + * inode number, so we don't repeat the procedure. + * + * new algorithm: + * due to complaints over did's being non-persistent, + * here's the current hack to provide semi-persistent + * did's: + * 1) we reserve the first bit for file ids. + * 2) the next 7 bits are for the device. + * 3) the remaining 24 bits are for the inode. + * + * both the inode and device information are actually hashes + * that are then truncated to the requisite bit length. + * + * it should be okay to use lstat to deal with symlinks. + */ #ifdef USE_LASTDID - aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff)); + 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 */ + lstp = lstat(upath, &lst) < 0 ? st : &lst; + aint = htonl(CNID(lstp, 1)); #endif /* USE_LASTDID */ - } + } - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); + break; - case FILPBIT_DFLEN : - aint = htonl( st->st_size ); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; + case FILPBIT_DFLEN : + aint = htonl( st->st_size ); + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); + break; - case FILPBIT_RFLEN : - if ( isad ) { - aint = htonl( ad_getentrylen( adp, ADEID_RFORK )); - } else { - aint = 0; - } - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - break; + case FILPBIT_RFLEN : + if ( adp ) { + aint = htonl( ad_getentrylen( adp, ADEID_RFORK )); + } else { + aint = 0; + } + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); + break; - /* Current client needs ProDOS info block for this file. - Use simple heuristic and let the Mac "type" string tell - us what the PD file code should be. Everything gets a - subtype of 0x0000 unless the original value was hashed - to "pXYZ" when we created it. See IA, Ver 2. - */ - case FILPBIT_PDINFO : - if ( isad ) { - memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 ); - - if ( memcmp( fdType, "TEXT", 4 ) == 0 ) { - achar = '\x04'; - ashort = 0x0000; - } - else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) { - achar = '\xff'; - ashort = 0x0000; - } - else if ( memcmp( fdType, "PS16", 4 ) == 0 ) { - achar = '\xb3'; - ashort = 0x0000; - } - else if ( memcmp( fdType, "BINA", 4 ) == 0 ) { - achar = '\x00'; - ashort = 0x0000; - } - else if ( fdType[0] == 'p' ) { - achar = fdType[1]; - ashort = (fdType[2] * 256) + fdType[3]; - } - else { - achar = '\x00'; - ashort = 0x0000; - } + /* Current client needs ProDOS info block for this file. + Use simple heuristic and let the Mac "type" string tell + us what the PD file code should be. Everything gets a + subtype of 0x0000 unless the original value was hashed + to "pXYZ" when we created it. See IA, Ver 2. + */ + case FILPBIT_PDINFO : + if ( adp ) { + memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 ); + + if ( memcmp( fdType, "TEXT", 4 ) == 0 ) { + achar = '\x04'; + ashort = 0x0000; + } + else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) { + achar = '\xff'; + ashort = 0x0000; + } + else if ( memcmp( fdType, "PS16", 4 ) == 0 ) { + achar = '\xb3'; + ashort = 0x0000; + } + else if ( memcmp( fdType, "BINA", 4 ) == 0 ) { + achar = '\x00'; + ashort = 0x0000; + } + else if ( fdType[0] == 'p' ) { + achar = fdType[1]; + ashort = (fdType[2] * 256) + fdType[3]; } else { achar = '\x00'; ashort = 0x0000; } + } + else { + achar = '\x00'; + ashort = 0x0000; + } - *data++ = achar; - *data++ = 0; - memcpy(data, &ashort, sizeof( ashort )); - data += sizeof( ashort ); - memset(data, 0, sizeof( ashort )); - data += sizeof( ashort ); - break; + *data++ = achar; + *data++ = 0; + memcpy(data, &ashort, sizeof( ashort )); + data += sizeof( ashort ); + memset(data, 0, sizeof( ashort )); + data += sizeof( ashort ); + break; - default : - if ( isad ) { - ad_close( adp, ADFLAGS_HF ); - } - return( AFPERR_BITMAP ); - } - bitmap = bitmap>>1; - bit++; + default : + return( AFPERR_BITMAP ); } - if ( nameoff ) { - ashort = htons( data - buf ); - memcpy(nameoff, &ashort, sizeof( ashort )); - if ((aint = strlen( path )) > MACFILELEN) - aint = MACFILELEN; - *data++ = aint; - memcpy(data, path, aint ); - data += aint; - } - if ( isad ) { - ad_close( adp, ADFLAGS_HF ); - } - *buflen = data - buf; - + bitmap = bitmap>>1; + bit++; + } + if ( nameoff ) { + ashort = htons( data - buf ); + memcpy(nameoff, &ashort, sizeof( ashort )); + if ((aint = strlen( path )) > MACFILELEN) + aint = MACFILELEN; + *data++ = aint; + memcpy(data, path, aint ); + data += aint; + } + *buflen = data - buf; + return (AFP_OK); +} + +/* ----------------------- */ +int getfilparams(struct vol *vol, + u_int16_t bitmap, + char *path, struct dir *dir, struct stat *st, + char *buf, int *buflen ) +{ + struct adouble ad, *adp; + struct ofork *of; + char *upath; + u_int16_t attrbits = 0; + int rc; #ifdef DEBUG - LOG(log_info, logtype_default, "end getfilparams:"); + LOG(log_info, logtype_afpd, "begin getfilparams:"); #endif /* DEBUG */ - return( AFP_OK ); - } - - int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct stat st; - struct adouble ad, *adp; - struct vol *vol; - struct dir *dir; - struct ofork *of; - char *path, *upath; - int creatf, did, openf, retvalue = AFP_OK; - u_int16_t vid; -#ifdef FORCE_UIDGID - uidgidset *uidgid; -#endif /* FORCE_UIDGID */ + upath = mtoupath(vol, path); + if ((of = of_findname(upath, st))) { + adp = of->of_ad; + attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0); + attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0); + + } else { + memset(&ad, 0, sizeof(ad)); + adp = &ad; + } + if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) { + adp = NULL; + } + else { +#if 0 + /* FIXME + we need to check if the file is open by another process. + it's slow so we only do it if we have to: + - bitmap is requested. + - we don't already have the answer! + */ + if ((bitmap & (1 << FILPBIT_ATTR))) { + if (!(attrbits & ATTRBIT_ROPEN)) { + } + if (!(attrbits & ATTRBIT_DOPEN)) { + } + } +#endif + } + rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits); + if ( adp ) { + ad_close( adp, ADFLAGS_HF ); + } #ifdef DEBUG - LOG(log_info, logtype_default, "begin afp_createfile:"); + LOG(log_info, logtype_afpd, "end getfilparams:"); #endif /* DEBUG */ - *rbuflen = 0; - ibuf++; - creatf = (unsigned char) *ibuf++; - - memcpy(&vid, ibuf, sizeof( vid )); - ibuf += sizeof( vid ); - - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM ); - } - - if (vol->v_flags & AFPVOL_RO) - return AFPERR_VLOCK; - - memcpy(&did, ibuf, sizeof( did)); - ibuf += sizeof( did ); - - if (( dir = dirsearch( vol, did )) == NULL ) { - return( AFPERR_NOOBJ ); - } - - if (( path = cname( vol, dir, &ibuf )) == NULL ) { - return( AFPERR_NOOBJ ); - } + return( rc ); +} - if (!wincheck(vol, path)) - return AFPERR_PARAM; +/* ----------------------------- */ +int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + struct stat st; + struct adouble ad, *adp; + struct vol *vol; + struct dir *dir; + struct ofork *of = NULL; + char *path, *upath; + int creatf, did, openf, retvalue = AFP_OK; + u_int16_t vid; + int ret; +#ifdef DEBUG + LOG(log_info, logtype_afpd, "begin afp_createfile:"); +#endif /* DEBUG */ - upath = mtoupath(vol, path); + *rbuflen = 0; + ibuf++; + creatf = (unsigned char) *ibuf++; - if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/')) - return AFPERR_PARAM; + memcpy(&vid, ibuf, sizeof( vid )); + ibuf += sizeof( vid ); - if (!validupath(vol, upath)) - return AFPERR_EXIST; + if (( vol = getvolbyvid( vid )) == NULL ) { + return( AFPERR_PARAM ); + } - /* check for vetoed filenames */ - if (veto_file(vol->v_veto, upath)) - return AFPERR_EXIST; + if (vol->v_flags & AFPVOL_RO) + return AFPERR_VLOCK; - if ((of = of_findname(vol, curdir, path))) { - adp = of->of_ad; - } else { - memset(&ad, 0, sizeof(ad)); - adp = &ad; - } - if ( creatf) { - /* on a hard create, fail if file exists and is open */ - if ((stat(upath, &st) == 0) && of) - return AFPERR_BUSY; - openf = O_RDWR|O_CREAT|O_TRUNC; - } else { - openf = O_RDWR|O_CREAT|O_EXCL; - } + memcpy(&did, ibuf, sizeof( did)); + ibuf += sizeof( did ); -#ifdef FORCE_UIDGID + if (( dir = dirlookup( vol, did )) == NULL ) { + return( AFPERR_NOOBJ ); + } - /* preserve current euid, egid */ - save_uidgid ( uidgid ); + if (( path = cname( vol, dir, &ibuf )) == NULL ) { + return( AFPERR_NOOBJ ); + } - /* perform all switching of users */ - set_uidgid ( vol ); + upath = mtoupath(vol, path); + if (0 != (ret = check_name(vol, upath))) + return ret; -#endif /* FORCE_UIDGID */ + ret = stat(upath, &st); + /* if upath is deleted we already in trouble anyway */ + if (!ret && (of = of_findname(upath, &st))) { + adp = of->of_ad; + } else { + memset(&ad, 0, sizeof(ad)); + adp = &ad; + } + if ( creatf) { + /* on a hard create, fail if file exists and is open */ + if (!ret && of) + return AFPERR_BUSY; + openf = O_RDWR|O_CREAT|O_TRUNC; + } else { + /* on a soft create, if the file is open then ad_open won't fail + because open syscall is not called + */ + if (of) { + return AFPERR_EXIST; + } + openf = O_RDWR|O_CREAT|O_EXCL; + } - if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF, - openf, 0666, adp) < 0 ) { - switch ( errno ) { - case EEXIST : -#ifdef FORCE_UIDGID - /* bring everything back to old euid, egid */ - restore_uidgid ( uidgid ); -#endif /* FORCE_UIDGID */ - return( AFPERR_EXIST ); - case EACCES : -#ifdef FORCE_UIDGID - /* bring everything back to old euid, egid */ - restore_uidgid ( uidgid ); -#endif /* FORCE_UIDGID */ - return( AFPERR_ACCESS ); - case ENOENT: - /* on noadouble volumes, just creating the data fork is ok */ - if (vol_noadouble(vol) && (stat(upath, &st) == 0)) - goto createfile_done; - /* fallthrough */ - default : -#ifdef FORCE_UIDGID - /* bring everything back to old euid, egid */ - restore_uidgid ( uidgid ); -#endif /* FORCE_UIDGID */ - return( AFPERR_PARAM ); - } + if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF, + openf, 0666, adp) < 0 ) { + switch ( errno ) { + case EEXIST : + return( AFPERR_EXIST ); + case EACCES : + return( AFPERR_ACCESS ); + case ENOENT: + /* on noadouble volumes, just creating the data fork is ok */ + if (vol_noadouble(vol) && (stat(upath, &st) == 0)) + goto createfile_done; + /* fallthrough */ + default : + return( AFPERR_PARAM ); } + } - ad_setentrylen( adp, ADEID_NAME, strlen( path )); - memcpy(ad_entry( adp, ADEID_NAME ), path, - ad_getentrylen( adp, ADEID_NAME )); - ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF ); - ad_close( adp, ADFLAGS_DF|ADFLAGS_HF ); + ad_setentrylen( adp, ADEID_NAME, strlen( path )); + memcpy(ad_entry( adp, ADEID_NAME ), path, + ad_getentrylen( adp, ADEID_NAME )); + ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF ); + ad_close( adp, ADFLAGS_DF|ADFLAGS_HF ); createfile_done: #ifdef DROPKLUDGE - if (vol->v_flags & AFPVOL_DROPBOX) { - retvalue = matchfile2dirperms(upath, vol, did); - } + if (vol->v_flags & AFPVOL_DROPBOX) { + retvalue = matchfile2dirperms(upath, vol, did); + } #endif /* DROPKLUDGE */ - setvoltime(obj, vol ); + setvoltime(obj, vol ); #ifdef DEBUG - LOG(log_info, logtype_default, "end afp_createfile"); + LOG(log_info, logtype_afpd, "end afp_createfile"); #endif /* DEBUG */ -#ifdef FORCE_UIDGID - /* bring everything back to old euid, egid */ - restore_uidgid ( uidgid ); -#endif /* FORCE_UIDGID */ - - return (retvalue); - } + return (retvalue); +} - int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct vol *vol; - struct dir *dir; - char *path; - int did, rc; - u_int16_t vid, bitmap; +int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + struct vol *vol; + struct dir *dir; + char *path; + int did, rc; + u_int16_t vid, bitmap; #ifdef DEBUG - LOG(log_info, logtype_default, "begin afp_setfilparams:"); + LOG(log_info, logtype_afpd, "begin afp_setfilparams:"); #endif /* DEBUG */ - *rbuflen = 0; - ibuf += 2; + *rbuflen = 0; + ibuf += 2; - memcpy(&vid, ibuf, sizeof( vid )); - ibuf += sizeof( vid ); - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM ); - } + memcpy(&vid, ibuf, sizeof( vid )); + ibuf += sizeof( vid ); + if (( vol = getvolbyvid( vid )) == NULL ) { + return( AFPERR_PARAM ); + } - if (vol->v_flags & AFPVOL_RO) - return AFPERR_VLOCK; + if (vol->v_flags & AFPVOL_RO) + return AFPERR_VLOCK; - memcpy(&did, ibuf, sizeof( did )); - ibuf += sizeof( did ); - if (( dir = dirsearch( vol, did )) == NULL ) { - return( AFPERR_NOOBJ ); - } + memcpy(&did, ibuf, sizeof( did )); + ibuf += sizeof( did ); + if (( dir = dirlookup( vol, did )) == NULL ) { + return( AFPERR_NOOBJ ); + } - memcpy(&bitmap, ibuf, sizeof( bitmap )); - bitmap = ntohs( bitmap ); - ibuf += sizeof( bitmap ); + memcpy(&bitmap, ibuf, sizeof( bitmap )); + bitmap = ntohs( bitmap ); + ibuf += sizeof( bitmap ); - if (( path = cname( vol, dir, &ibuf )) == NULL ) { - return( AFPERR_NOOBJ ); - } + if (( path = cname( vol, dir, &ibuf )) == NULL ) { + return( AFPERR_NOOBJ ); + } - if ((u_long)ibuf & 1 ) { - ibuf++; - } + if ( *path == '\0' ) { + return( AFPERR_BADTYPE ); /* it's a directory */ + } - if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) { - setvoltime(obj, vol ); - } + if ((u_long)ibuf & 1 ) { + ibuf++; + } + + if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) { + setvoltime(obj, vol ); + } #ifdef DEBUG - LOG(log_info, logtype_default, "end afp_setfilparams:"); + LOG(log_info, logtype_afpd, "end afp_setfilparams:"); #endif /* DEBUG */ - return( rc ); - } + return( rc ); +} +/* + * cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic + * +*/ - int setfilparams(struct vol *vol, - char *path, u_int16_t bitmap, char *buf ) - { - struct adouble ad, *adp; - struct ofork *of; - struct extmap *em; - int bit = 0, isad = 1, err = AFP_OK; - char *upath; - u_char achar, *fdType, xyy[4]; - u_int16_t ashort, bshort; - u_int32_t aint; - struct utimbuf ut; +int setfilparams(struct vol *vol, + char *path, u_int16_t bitmap, char *buf ) +{ + struct adouble ad, *adp; + struct ofork *of; + struct extmap *em; + int bit = 0, isad = 1, err = AFP_OK; + char *upath; + u_char achar, *fdType, xyy[4]; + u_int16_t ashort, bshort; + u_int32_t aint; + struct utimbuf ut; -#ifdef FORCE_UIDGID - uidgidset *uidgid; + int change_mdate = 0; + int change_parent_mdate = 0; + int newdate = 0; + struct timeval tv; - uidgid = malloc(sizeof(uidgidset)); -#endif /* FORCE_UIDGID */ #ifdef DEBUG - LOG(log_info, logtype_default, "begin setfilparams:"); + LOG(log_info, logtype_afpd, "begin setfilparams:"); #endif /* DEBUG */ - upath = mtoupath(vol, path); - if ((of = of_findname(vol, curdir, path))) { - adp = of->of_ad; - } else { - memset(&ad, 0, sizeof(ad)); - adp = &ad; + upath = mtoupath(vol, path); + if ((of = of_findname(upath, NULL))) { + adp = of->of_ad; + } else { + memset(&ad, 0, sizeof(ad)); + adp = &ad; + } + + if (check_access(upath, OPENACC_WR ) < 0) { + return AFPERR_ACCESS; + } + + if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF, + O_RDWR|O_CREAT, 0666, adp) < 0) { + /* for some things, we don't need an adouble header */ + if (bitmap & ~(1<>1; + bit++; } -#ifdef FORCE_UIDGID - save_uidgid ( uidgid ); - set_uidgid ( vol ); -#endif /* FORCE_UIDGID */ - - if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF, - O_RDWR|O_CREAT, 0666, adp) < 0) { - /* for some things, we don't need an adouble header */ - if (bitmap & ~(1<>1; - bit++; + case FILPBIT_FINFO : + change_mdate = 1; + + if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) + && ( + ((em = getextmap( path )) && + !memcmp(buf, em->em_type, sizeof( em->em_type )) && + !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator))) + || ((em = getdefextmap()) && + !memcmp(buf, em->em_type, sizeof( em->em_type )) && + !memcmp(buf + 4, em->em_creator,sizeof( em->em_creator))) + )) { + memcpy(buf, ufinderi, 8 ); } - switch( bit ) { - case FILPBIT_ATTR : - memcpy(&ashort, buf, sizeof( ashort )); - ad_getattr(adp, &bshort); - if ( ntohs( ashort ) & ATTRBIT_SETCLR ) { - bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR ); - } else { - bshort &= ~ashort; - } - ad_setattr(adp, bshort); - buf += sizeof( ashort ); - break; + memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 ); + buf += 32; + break; - case FILPBIT_CDATE : - memcpy(&aint, buf, sizeof(aint)); - ad_setdate(adp, AD_DATE_CREATE, aint); - buf += sizeof( aint ); + /* Client needs to set the ProDOS file info for this file. + Use defined strings for the simple cases, and convert + all else into pXYY per Inside Appletalk. Always set + the creator as "pdos". */ + case FILPBIT_PDINFO : + achar = *buf; + buf += 2; + memcpy(&ashort, buf, sizeof( ashort )); + ashort = ntohs( ashort ); + buf += 2; + + switch ( (unsigned int) achar ) + { + case 0x04 : + fdType = ( u_char *) "TEXT"; break; - case FILPBIT_MDATE : - memcpy(&aint, buf, sizeof( aint )); - if (isad) - ad_setdate(adp, AD_DATE_MODIFY, aint); - ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint); - utime(upath, &ut); - buf += sizeof( aint ); + case 0xff : + fdType = ( u_char *) "PSYS"; break; - case FILPBIT_BDATE : - memcpy(&aint, buf, sizeof(aint)); - ad_setdate(adp, AD_DATE_BACKUP, aint); - buf += sizeof( aint ); + case 0xb3 : + fdType = ( u_char *) "PS16"; break; - case FILPBIT_FINFO : - if ((memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 ) == 0) - && (em = getextmap( path )) && - (memcmp(buf, em->em_type, sizeof( em->em_type )) == 0) && - (memcmp(buf + 4, em->em_creator, - sizeof( em->em_creator )) == 0)) { - memcpy(buf, ufinderi, 8 ); - } - memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 ); - buf += 32; + case 0x00 : + fdType = ( u_char *) "BINA"; break; - /* Client needs to set the ProDOS file info for this file. - Use defined strings for the simple cases, and convert - all else into pXYY per Inside Appletalk. Always set - the creator as "pdos". */ - case FILPBIT_PDINFO : - achar = *buf; - buf += 2; - memcpy(&ashort, buf, sizeof( ashort )); - ashort = ntohs( ashort ); - buf += 2; - - switch ( (unsigned int) achar ) - { - case 0x04 : - fdType = ( u_char *) "TEXT"; - break; - - case 0xff : - fdType = ( u_char *) "PSYS"; - break; - - case 0xb3 : - fdType = ( u_char *) "PS16"; - break; - - case 0x00 : - fdType = ( u_char *) "BINA"; - break; - - default : - xyy[0] = ( u_char ) 'p'; - xyy[1] = achar; - xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff; - xyy[3] = ( u_char ) ashort & 0xff; - fdType = xyy; - break; - } - - memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 ); - memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 ); + default : + xyy[0] = ( u_char ) 'p'; + xyy[1] = achar; + xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff; + xyy[3] = ( u_char ) ashort & 0xff; + fdType = xyy; break; + } + memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 ); + memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 ); + break; - default : - err = AFPERR_BITMAP; - goto setfilparam_done; - } - bitmap = bitmap>>1; - bit++; + default : + err = AFPERR_BITMAP; + goto setfilparam_done; } + bitmap = bitmap>>1; + bit++; + } + setfilparam_done: - if (isad) { - ad_flush( adp, ADFLAGS_HF ); - ad_close( adp, ADFLAGS_HF ); + if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) { + newdate = AD_DATE_FROM_UNIX(tv.tv_sec); + } + if (newdate) { + if (isad) + ad_setdate(adp, AD_DATE_MODIFY, newdate); + ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate); + utime(upath, &ut); + } -#ifdef FORCE_UIDGID - restore_uidgid ( uidgid ); -#endif /* FORCE_UIDGID */ + if (isad) { + ad_flush( adp, ADFLAGS_HF ); + ad_close( adp, ADFLAGS_HF ); - } + } + + if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) { + newdate = AD_DATE_FROM_UNIX(tv.tv_sec); + bitmap = 1<newtmp; - strcpy( newname, path ); + newname = obj->newtmp; + strcpy( newname, path ); - p = ctoupath( vol, curdir, newname ); + upath = mtoupath(vol, newname ); + if (of_findname(upath, NULL)) + return AFPERR_DENYCONF; - if (( vol = getvolbyvid( dvid )) == NULL ) { - return( AFPERR_PARAM ); - } + p = ctoupath( vol, curdir, newname ); +#ifdef FORCE_UIDGID + /* FIXME svid != dvid && dvid's user can't read svid */ +#endif + if (( vol = getvolbyvid( dvid )) == NULL ) { + return( AFPERR_PARAM ); + } - if (vol->v_flags & AFPVOL_RO) - return AFPERR_VLOCK; + if (vol->v_flags & AFPVOL_RO) + return AFPERR_VLOCK; - if (( dir = dirsearch( vol, ddid )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( dir = dirlookup( vol, ddid )) == NULL ) { + return( AFPERR_PARAM ); + } - if (( path = cname( vol, dir, &ibuf )) == NULL ) { - return( AFPERR_NOOBJ ); - } - if ( *path != '\0' ) { - return( AFPERR_BADTYPE ); - } + if (( path = cname( vol, dir, &ibuf )) == NULL ) { + return( AFPERR_NOOBJ ); + } + if ( *path != '\0' ) { + return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */ + } - /* one of the handful of places that knows about the path type */ - if ( *ibuf++ != 2 ) { + /* one of the handful of places that knows about the path type */ + if ( *ibuf++ != 2 ) { + return( AFPERR_PARAM ); + } + if (( plen = (unsigned char)*ibuf++ ) != 0 ) { + strncpy( newname, ibuf, plen ); + newname[ plen ] = '\0'; + if (strlen(newname) != plen) { + /* there's \0 in newname, e.g. it's a pathname not + * only a filename. + */ return( AFPERR_PARAM ); } - if (( plen = (unsigned char)*ibuf++ ) != 0 ) { - strncpy( newname, ibuf, plen ); - newname[ plen ] = '\0'; - } - - if ( (err = copyfile(p, mtoupath(vol, newname ), newname, - vol_noadouble(vol))) < 0 ) { - return err; - } - - setvoltime(obj, vol ); + } + upath = mtoupath(vol, newname); + if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) { + return err; + } #ifdef DROPKLUDGE - if (vol->v_flags & AFPVOL_DROPBOX) { - retvalue=matchfile2dirperms(newname, vol, sdid); - } + if (vol->v_flags & AFPVOL_DROPBOX) { + retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */ + } #endif /* DROPKLUDGE */ + setvoltime(obj, vol ); + #ifdef DEBUG - LOG(log_info, logtype_default, "end afp_copyfile:"); + LOG(log_info, logtype_afpd, "end afp_copyfile:"); #endif /* DEBUG */ - return( retvalue ); - } + return( retvalue ); +} - static __inline__ int copy_all(const int dfd, const void *buf, - size_t buflen) - { - ssize_t cc; +static __inline__ int copy_all(const int dfd, const void *buf, + size_t buflen) +{ + ssize_t cc; #ifdef DEBUG - LOG(log_info, logtype_default, "begin copy_all:"); + LOG(log_info, logtype_afpd, "begin copy_all:"); #endif /* DEBUG */ - while (buflen > 0) { - if ((cc = write(dfd, buf, buflen)) < 0) { - switch (errno) { - case EINTR: - continue; - case EDQUOT: - case EFBIG: - case ENOSPC: - return AFPERR_DFULL; - case EROFS: - return AFPERR_VLOCK; - default: - return AFPERR_PARAM; - } + while (buflen > 0) { + if ((cc = write(dfd, buf, buflen)) < 0) { + switch (errno) { + case EINTR: + continue; + case EDQUOT: + case EFBIG: + case ENOSPC: + return AFPERR_DFULL; + case EROFS: + return AFPERR_VLOCK; + default: + return AFPERR_PARAM; } - buflen -= cc; } + buflen -= cc; + } #ifdef DEBUG - LOG(log_info, logtype_default, "end copy_all:"); + LOG(log_info, logtype_afpd, "end copy_all:"); #endif /* DEBUG */ - return AFP_OK; - } - - /* XXX: this needs to use ad_open and ad_lock. so, we need to - * pass in vol and path */ - int copyfile(src, dst, newname, noadouble ) - char *src, *dst, *newname; - const int noadouble; - { - struct adouble ad; - struct stat st; - char filebuf[8192]; - int sfd, dfd, len, err = AFP_OK; - ssize_t cc; + return AFP_OK; +} +/* XXX: this needs to use ad_open and ad_lock. so, we need to + * pass in vol and path */ +int copyfile(src, dst, newname, noadouble ) +char *src, *dst, *newname; +const int noadouble; +{ + struct adouble ad; + struct stat st; + char filebuf[8192]; + int sfd, dfd, len, err = AFP_OK; + ssize_t cc; + char dpath[ MAXPATHLEN + 1]; + int admode; #ifdef DEBUG - LOG(log_info, logtype_default, "begin copyfile:"); + LOG(log_info, logtype_afpd, "begin copyfile:"); #endif /* DEBUG */ - if (newname) { - if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) { + strcpy(dpath, ad_path( dst, ADFLAGS_HF )); + admode = ad_mode( dst, 0666 ); + if (newname) { + if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) { + switch ( errno ) { + case ENOENT : + break; /* just copy the data fork */ + case EACCES : + return( AFPERR_ACCESS ); + default : + return( AFPERR_PARAM ); + } + } else { + if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) { + close( sfd ); switch ( errno ) { case ENOENT : - break; /* just copy the data fork */ + return( AFPERR_NOOBJ ); case EACCES : return( AFPERR_ACCESS ); + case EROFS: + return AFPERR_VLOCK; default : return( AFPERR_PARAM ); } - } else { - if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT, - ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) { - close( sfd ); - switch ( errno ) { - case ENOENT : - return( AFPERR_NOOBJ ); - case EACCES : - return( AFPERR_ACCESS ); - case EROFS: - return AFPERR_VLOCK; - default : - return( AFPERR_PARAM ); - } - } + } - /* copy the file */ + /* copy the file */ #ifdef SENDFILE_FLAVOR_LINUX - if (fstat(sfd, &st) == 0) { - if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) { - switch (errno) { - case EDQUOT: - case EFBIG: - case ENOSPC: - err = AFPERR_DFULL; - break; - case EROFS: - err = AFPERR_VLOCK; - break; - default: - err = AFPERR_PARAM; - } + if (fstat(sfd, &st) == 0) { + if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) { + switch (errno) { + case EDQUOT: + case EFBIG: + case ENOSPC: + err = AFPERR_DFULL; + break; + case EROFS: + err = AFPERR_VLOCK; + break; + default: + err = AFPERR_PARAM; } - goto copyheader_done; } + goto copyheader_done; + } #endif /* SENDFILE_FLAVOR_LINUX */ - while (1) { - if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) { - if (errno == EINTR) - continue; - err = AFPERR_PARAM; - break; - } - - if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) - break; + while (1) { + if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) { + if (errno == EINTR) + continue; + err = AFPERR_PARAM; + break; } + if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) + break; + } + copyheader_done: - close(sfd); - close(dfd); - if (err < 0) { - unlink(ad_path(dst, ADFLAGS_HF)); - return err; - } + close(sfd); + close(dfd); + if (err < 0) { + unlink(dpath); + return err; } } + } - /* data fork copying */ - if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) { - switch ( errno ) { - case ENOENT : - return( AFPERR_NOOBJ ); - case EACCES : - return( AFPERR_ACCESS ); - default : - return( AFPERR_PARAM ); - } + /* data fork copying */ + if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) { + switch ( errno ) { + case ENOENT : + return( AFPERR_NOOBJ ); + case EACCES : + return( AFPERR_ACCESS ); + default : + return( AFPERR_PARAM ); } + } - if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) { - close( sfd ); - switch ( errno ) { - case ENOENT : - return( AFPERR_NOOBJ ); - case EACCES : - return( AFPERR_ACCESS ); - case EROFS: - return AFPERR_VLOCK; - default : - return( AFPERR_PARAM ); - } + if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) { + close( sfd ); + switch ( errno ) { + case ENOENT : + return( AFPERR_NOOBJ ); + case EACCES : + return( AFPERR_ACCESS ); + case EROFS: + return AFPERR_VLOCK; + default : + return( AFPERR_PARAM ); } + } #ifdef SENDFILE_FLAVOR_LINUX - if (fstat(sfd, &st) == 0) { - if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) { - switch (errno) { - case EDQUOT: - case EFBIG: - case ENOSPC: - err = AFPERR_DFULL; - break; - default: - err = AFPERR_PARAM; - } + if (fstat(sfd, &st) == 0) { + if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) { + switch (errno) { + case EDQUOT: + case EFBIG: + case ENOSPC: + err = AFPERR_DFULL; + break; + default: + err = AFPERR_PARAM; } - goto copydata_done; } + goto copydata_done; + } #endif /* SENDFILE_FLAVOR_LINUX */ - while (1) { - if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) { - if (errno == EINTR) - continue; + while (1) { + if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) { + if (errno == EINTR) + continue; - err = AFPERR_PARAM; - break; - } + err = AFPERR_PARAM; + break; + } - if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) { - break; - } + if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) { + break; } + } copydata_done: - close(sfd); - close(dfd); - if (err < 0) { - unlink(ad_path(dst, ADFLAGS_HF)); - unlink(dst); - return err; - } + close(sfd); + close(dfd); + if (err < 0) { + unlink(dpath); + unlink(dst); + return err; + } - if (newname) { - memset(&ad, 0, sizeof(ad)); - if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT, - 0666, &ad) < 0 ) { - switch ( errno ) { - case ENOENT : - return noadouble ? AFP_OK : AFPERR_NOOBJ; - case EACCES : - return( AFPERR_ACCESS ); - case EROFS: - return AFPERR_VLOCK; - default : - return( AFPERR_PARAM ); - } + if (newname) { + memset(&ad, 0, sizeof(ad)); + if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT, + 0666, &ad) < 0 ) { + switch ( errno ) { + case ENOENT : + return noadouble ? AFP_OK : AFPERR_NOOBJ; + case EACCES : + return( AFPERR_ACCESS ); + case EROFS: + return AFPERR_VLOCK; + default : + return( AFPERR_PARAM ); } - - len = strlen( newname ); - ad_setentrylen( &ad, ADEID_NAME, len ); - memcpy(ad_entry( &ad, ADEID_NAME ), newname, len ); - ad_flush( &ad, ADFLAGS_HF ); - ad_close( &ad, ADFLAGS_HF ); } + len = strlen( newname ); + ad_setentrylen( &ad, ADEID_NAME, len ); + memcpy(ad_entry( &ad, ADEID_NAME ), newname, len ); + ad_flush( &ad, ADFLAGS_HF ); + ad_close( &ad, ADFLAGS_HF ); + } + #ifdef DEBUG - LOG(log_info, logtype_default, "end copyfile:"); + LOG(log_info, logtype_afpd, "end copyfile:"); #endif /* DEBUG */ - return( AFP_OK ); - } + return( AFP_OK ); +} - int deletefile( file ) - char *file; - { - struct adouble ad; - int adflags, err = AFP_OK; - int locktype = ADLOCK_WR; - int openmode = O_RDWR; +/* ----------------------------------- + checkAttrib: 1 check kFPDeleteInhibitBit + ie deletfile called by afp_delete + + when deletefile is called we don't have lock on it, file is closed (for us) + untrue if called by renamefile +*/ +int deletefile( file, checkAttrib ) +char *file; +int checkAttrib; +{ + struct adouble ad; + int adflags, err = AFP_OK; + int locktype = ADLOCK_WR; + int openmode = O_RDWR; #ifdef DEBUG - LOG(log_info, logtype_default, "begin deletefile:"); + LOG(log_info, logtype_afpd, "begin deletefile:"); #endif /* DEBUG */ - while(1) { - /* - * If can't open read/write then try again read-only. If it's open - * read-only, we must do a read lock instead of a write lock. - */ - /* try to open both at once */ - adflags = ADFLAGS_DF|ADFLAGS_HF; - memset(&ad, 0, sizeof(ad)); - if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) { - switch (errno) { - case ENOENT: - adflags = ADFLAGS_DF; - /* that failed. now try to open just the data fork */ - memset(&ad, 0, sizeof(ad)); - if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) { - switch (errno) { - case ENOENT: - return AFPERR_NOOBJ; - case EACCES: - if(openmode == O_RDWR) { - openmode = O_RDONLY; - locktype = ADLOCK_RD; - continue; - } else { - return AFPERR_ACCESS; - } - case EROFS: - return AFPERR_VLOCK; - default: - return AFPERR_PARAM; + while(1) { + /* + * If can't open read/write then try again read-only. If it's open + * read-only, we must do a read lock instead of a write lock. + */ + /* try to open both at once */ + adflags = ADFLAGS_DF|ADFLAGS_HF; + memset(&ad, 0, sizeof(ad)); + if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) { + switch (errno) { + case ENOENT: + adflags = ADFLAGS_DF; + /* that failed. now try to open just the data fork */ + memset(&ad, 0, sizeof(ad)); + if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) { + switch (errno) { + case ENOENT: + return AFPERR_NOOBJ; + case EACCES: + if(openmode == O_RDWR) { + openmode = O_RDONLY; + locktype = ADLOCK_RD; + continue; + } else { + return AFPERR_ACCESS; } + case EROFS: + return AFPERR_VLOCK; + default: + return AFPERR_PARAM; } - break; + } + break; - case EACCES: - if(openmode == O_RDWR) { - openmode = O_RDONLY; - locktype = ADLOCK_RD; - continue; - } else { - return AFPERR_ACCESS; - } - case EROFS: - return AFPERR_VLOCK; - default: - return( AFPERR_PARAM ); + case EACCES: + if(openmode == O_RDWR) { + openmode = O_RDONLY; + locktype = ADLOCK_RD; + continue; + } else { + return AFPERR_ACCESS; } + case EROFS: + return AFPERR_VLOCK; + default: + return( AFPERR_PARAM ); } - break; /* from the while */ } + break; /* from the while */ + } + /* + * Does kFPDeleteInhibitBit (bit 8) set? + */ + if (checkAttrib && (adflags & ADFLAGS_HF)) { + u_int16_t bshort; - if ((adflags & ADFLAGS_HF) && - (ad_tmplock(&ad, ADEID_RFORK, locktype, 0, 0) < 0 )) { + ad_getattr(&ad, &bshort); + if ((bshort & htons(ATTRBIT_NODELETE))) { + ad_close( &ad, adflags ); + return(AFPERR_OLOCK); + } + } + + if ((adflags & ADFLAGS_HF) ) { + /* FIXME we have a pb here because we want to know if a file is open + * there's a 'priority inversion' if you can't open the ressource fork RW + * you can delete it if it's open because you can't get a write lock. + * + * ADLOCK_FILELOCK means the whole ressource fork, not only after the + * metadatas + * + * FIXME it doesn't for RFORK open read only and fork open without deny mode + */ + if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) { ad_close( &ad, adflags ); return( AFPERR_BUSY ); } + } - if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) { - err = AFPERR_BUSY; - goto delete_unlock; - } + if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) { + err = AFPERR_BUSY; + goto delete_unlock; + } - if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) { - switch ( errno ) { - case EPERM: - case EACCES : - err = AFPERR_ACCESS; - goto delete_unlock; - case EROFS: - err = AFPERR_VLOCK; - goto delete_unlock; - case ENOENT : - break; - default : - err = AFPERR_PARAM; - goto delete_unlock; - } + if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) { + switch ( errno ) { + case EPERM: + case EACCES : + err = AFPERR_ACCESS; + goto delete_unlock; + case EROFS: + err = AFPERR_VLOCK; + goto delete_unlock; + case ENOENT : + break; + default : + err = AFPERR_PARAM; + goto delete_unlock; } + } - if ( unlink( file ) < 0 ) { - switch ( errno ) { - case EPERM: - case EACCES : - err = AFPERR_ACCESS; - break; - case EROFS: - err = AFPERR_VLOCK; - break; - case ENOENT : - break; - default : - err = AFPERR_PARAM; - break; - } + if ( unlink( file ) < 0 ) { + switch ( errno ) { + case EPERM: + case EACCES : + err = AFPERR_ACCESS; + break; + case EROFS: + err = AFPERR_VLOCK; + break; + case ENOENT : + break; + default : + err = AFPERR_PARAM; + break; } + } delete_unlock: - if (adflags & ADFLAGS_HF) - ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR, 0, 0); - ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0); - ad_close( &ad, adflags ); + if (adflags & ADFLAGS_HF) + ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0); + ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0); + ad_close( &ad, adflags ); #ifdef DEBUG - LOG(log_info, logtype_default, "end deletefile:"); + LOG(log_info, logtype_afpd, "end deletefile:"); #endif /* DEBUG */ - return err; - } + return err; +} #ifdef CNID_DB - /* return a file id */ - int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct stat st; - struct adouble ad; - struct vol *vol; - struct dir *dir; - char *path, *upath; - int len; - cnid_t did, id; - u_short vid; +/* return a file id */ +int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + struct stat st; + struct adouble ad; + struct vol *vol; + struct dir *dir; + char *path, *upath; + int len; + cnid_t did, id; + u_short vid; #ifdef DEBUG - LOG(log_info, logtype_default, "begin afp_createid:"); + LOG(log_info, logtype_afpd, "begin afp_createid:"); #endif /* DEBUG */ - *rbuflen = 0; - ibuf += 2; + *rbuflen = 0; + ibuf += 2; - memcpy(&vid, ibuf, sizeof(vid)); - ibuf += sizeof(vid); + memcpy(&vid, ibuf, sizeof(vid)); + ibuf += sizeof(vid); - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM); - } + if (( vol = getvolbyvid( vid )) == NULL ) { + return( AFPERR_PARAM); + } - if (vol->v_flags & AFPVOL_RO) - return AFPERR_VLOCK; + if (vol->v_flags & AFPVOL_RO) + return AFPERR_VLOCK; - memcpy(&did, ibuf, sizeof( did )); - ibuf += sizeof(did); + memcpy(&did, ibuf, sizeof( did )); + ibuf += sizeof(did); - if (( dir = dirsearch( vol, did )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( dir = dirlookup( vol, did )) == NULL ) { + return( AFPERR_PARAM ); + } - if (( path = cname( vol, dir, &ibuf )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( path = cname( vol, dir, &ibuf )) == NULL ) { + return( AFPERR_PARAM ); + } - if ( *path == '\0' ) { - return( AFPERR_BADTYPE ); - } + if ( *path == '\0' ) { + return( AFPERR_BADTYPE ); + } - upath = mtoupath(vol, path); - if (stat(upath, &st) < 0) { - switch (errno) { - case EPERM: - case EACCES: - return AFPERR_ACCESS; - case ENOENT: - return AFPERR_NOOBJ; - default: - return AFPERR_PARAM; - } + upath = mtoupath(vol, path); + if (stat(upath, &st) < 0) { + switch (errno) { + case EPERM: + case EACCES: + return AFPERR_ACCESS; + case ENOENT: + return AFPERR_NOOBJ; + default: + return AFPERR_PARAM; } + } - if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) { - memcpy(rbuf, &id, sizeof(id)); - *rbuflen = sizeof(id); - return AFPERR_EXISTID; - } + if (id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath))) { + memcpy(rbuf, &id, sizeof(id)); + *rbuflen = sizeof(id); + return AFPERR_EXISTID; + } #if AD_VERSION > AD_VERSION1 - memset(&ad, 0, sizeof(ad)); - if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) { - memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id)); - ad_close(&ad, ADFLAGS_HF); - } + memset(&ad, 0, sizeof(ad)); + if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) { + memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id)); + ad_close(&ad, ADFLAGS_HF); + } #endif /* AD_VERSION > AD_VERSION1 */ - if (id = cnid_add(vol->v_db, &st, did, upath, len, id)) { - memcpy(rbuf, &id, sizeof(id)); - *rbuflen = sizeof(id); - return AFP_OK; - } + if (id = cnid_add(vol->v_db, &st, did, upath, len, id) != CNID_INVALID) { + memcpy(rbuf, &id, sizeof(id)); + *rbuflen = sizeof(id); + return AFP_OK; + } #ifdef DEBUG - LOG(log_info, logtype_default, "ending afp_createid...:"); + LOG(log_info, logtype_afpd, "ending afp_createid...:"); #endif /* DEBUG */ - switch (errno) { - case EROFS: - return AFPERR_VLOCK; - break; - case EPERM: - case EACCES: - return AFPERR_ACCESS; - break; - default: - LOG(log_error, logtype_default, "afp_createid: cnid_add: %s", strerror(errno)); - return AFPERR_PARAM; - } + switch (errno) { + case EROFS: + return AFPERR_VLOCK; + break; + case EPERM: + case EACCES: + return AFPERR_ACCESS; + break; + default: + LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno)); + return AFPERR_PARAM; } +} - /* resolve a file id */ - int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct stat st; - struct vol *vol; - struct dir *dir; - char *upath; - int err, buflen; - cnid_t id; - u_int16_t vid, bitmap; +/* resolve a file id */ +int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + struct stat st; + struct vol *vol; + struct dir *dir; + char *upath; + int err, buflen; + cnid_t id; + u_int16_t vid, bitmap; + + static char buffer[12 + MAXPATHLEN + 1]; + int len = 12 + MAXPATHLEN + 1; #ifdef DEBUG - LOG(log_info, logtype_default, "begin afp_resolveid:"); + LOG(log_info, logtype_afpd, "begin afp_resolveid:"); #endif /* DEBUG */ - *rbuflen = 0; - ibuf += 2; + *rbuflen = 0; + ibuf += 2; - memcpy(&vid, ibuf, sizeof(vid)); - ibuf += sizeof(vid); + memcpy(&vid, ibuf, sizeof(vid)); + ibuf += sizeof(vid); - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM); - } + if (( vol = getvolbyvid( vid )) == NULL ) { + return( AFPERR_PARAM); + } - memcpy(&id, ibuf, sizeof( id )); - ibuf += sizeof(id); + memcpy(&id, ibuf, sizeof( id )); + ibuf += sizeof(id); - if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) { - return AFPERR_BADID; - } + if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) { + return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */ + } - if (( dir = dirsearch( vol, id )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( dir = dirlookup( vol, id )) == NULL ) { + return AFPERR_NOID; /* idem AFPERR_PARAM */ + } - if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) { - switch (errno) { - case EACCES: - case EPERM: - return AFPERR_ACCESS; - case ENOENT: - return AFPERR_NOID; - default: - return AFPERR_PARAM; - } + if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) { + switch (errno) { + case EACCES: + case EPERM: + return AFPERR_ACCESS; + case ENOENT: + return AFPERR_NOID; + default: + return AFPERR_PARAM; } + } - /* directories are bad */ - if (S_ISDIR(st.st_mode)) - return AFPERR_BADTYPE; + /* directories are bad */ + if (S_ISDIR(st.st_mode)) + return AFPERR_BADTYPE; - memcpy(&bitmap, ibuf, sizeof(bitmap)); - bitmap = ntohs( bitmap ); + memcpy(&bitmap, ibuf, sizeof(bitmap)); + bitmap = ntohs( bitmap ); - if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st, - rbuf + sizeof(bitmap), &buflen)) != AFP_OK) - return err; + if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st, + rbuf + sizeof(bitmap), &buflen)) != AFP_OK) + return err; - *rbuflen = buflen + sizeof(bitmap); - memcpy(rbuf, ibuf, sizeof(bitmap)); + *rbuflen = buflen + sizeof(bitmap); + memcpy(rbuf, ibuf, sizeof(bitmap)); #ifdef DEBUG - LOG(log_info, logtype_default, "end afp_resolveid:"); + LOG(log_info, logtype_afpd, "end afp_resolveid:"); #endif /* DEBUG */ - return AFP_OK; - } + return AFP_OK; +} - int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct stat st; - struct vol *vol; - struct dir *dir; - char *upath; - int err; - cnid_t id; - u_short vid; +int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + struct stat st; + struct vol *vol; + struct dir *dir; + char *upath; + int err; + cnid_t id; + cnid_t fileid; + u_short vid; + static char buffer[12 + MAXPATHLEN + 1]; + int len = 12 + MAXPATHLEN + 1; #ifdef DEBUG - LOG(log_info, logtype_default, "begin afp_deleteid:"); + LOG(log_info, logtype_afpd, "begin afp_deleteid:"); #endif /* DEBUG */ - *rbuflen = 0; - ibuf += 2; + *rbuflen = 0; + ibuf += 2; - memcpy(&vid, ibuf, sizeof(vid)); - ibuf += sizeof(vid); + memcpy(&vid, ibuf, sizeof(vid)); + ibuf += sizeof(vid); - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM); - } + if (( vol = getvolbyvid( vid )) == NULL ) { + return( AFPERR_PARAM); + } - if (vol->v_flags & AFPVOL_RO) - return AFPERR_VLOCK; + if (vol->v_flags & AFPVOL_RO) + return AFPERR_VLOCK; - memcpy(&id, ibuf, sizeof( id )); - ibuf += sizeof(id); + memcpy(&id, ibuf, sizeof( id )); + ibuf += sizeof(id); + fileid = id; - if ((upath = cnid_resolve(vol->v_db, &id)) == NULL) { - return AFPERR_NOID; - } + if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) { + return AFPERR_NOID; + } - if (( dir = dirsearch( vol, id )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( dir = dirlookup( vol, id )) == NULL ) { + return( AFPERR_PARAM ); + } - err = AFP_OK; - if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) { - switch (errno) { - case EACCES: - case EPERM: - return AFPERR_ACCESS; - case ENOENT: - /* still try to delete the id */ - err = AFPERR_NOOBJ; - break; - default: - return AFPERR_PARAM; - } + err = AFP_OK; + if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) { + switch (errno) { + case EACCES: + case EPERM: + return AFPERR_ACCESS; + case ENOENT: + /* still try to delete the id */ + err = AFPERR_NOOBJ; + break; + default: + return AFPERR_PARAM; } + } - /* directories are bad */ - if (S_ISDIR(st.st_mode)) - return AFPERR_BADTYPE; + /* directories are bad */ + if (S_ISDIR(st.st_mode)) + return AFPERR_BADTYPE; - if (cnid_delete(vol->v_db, id)) { - switch (errno) { - case EROFS: - return AFPERR_VLOCK; - case EPERM: - case EACCES: - return AFPERR_ACCESS; - default: - return AFPERR_PARAM; - } + if (cnid_delete(vol->v_db, fileid)) { + switch (errno) { + case EROFS: + return AFPERR_VLOCK; + case EPERM: + case EACCES: + return AFPERR_ACCESS; + default: + return AFPERR_PARAM; } + } #ifdef DEBUG - LOG(log_info, logtype_default, "end afp_deleteid:"); + LOG(log_info, logtype_afpd, "end afp_deleteid:"); #endif /* DEBUG */ - return err; - } + return err; +} #endif /* CNID_DB */ #define APPLETEMP ".AppleTempXXXXXX" - int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen ) - AFPObj *obj; - char *ibuf, *rbuf; - int ibuflen, *rbuflen; - { - struct stat srcst, destst; - struct vol *vol; - struct dir *dir, *sdir; - char *spath, temp[17], *path, *p; - char *supath, *upath; - int err; +int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen ) +AFPObj *obj; +char *ibuf, *rbuf; +int ibuflen, *rbuflen; +{ + struct stat srcst, destst; + struct vol *vol; + struct dir *dir, *sdir; + char *spath, temp[17], *path, *p; + char *supath, *upath; + int err; + struct adouble ads; + struct adouble add; + struct adouble *adsp; + struct adouble *addp; + struct ofork *s_of; + struct ofork *d_of; + #ifdef CNID_DB - int slen, dlen; + int slen, dlen; #endif /* CNID_DB */ - u_int32_t sid, did; - u_int16_t vid; + u_int32_t sid, did; + u_int16_t vid; #ifdef DEBUG - LOG(log_info, logtype_default, "begin afp_exchangefiles:"); + LOG(log_info, logtype_afpd, "begin afp_exchangefiles:"); #endif /* DEBUG */ - *rbuflen = 0; - ibuf += 2; + *rbuflen = 0; + ibuf += 2; - memcpy(&vid, ibuf, sizeof(vid)); - ibuf += sizeof(vid); + memcpy(&vid, ibuf, sizeof(vid)); + ibuf += sizeof(vid); - if (( vol = getvolbyvid( vid )) == NULL ) { - return( AFPERR_PARAM); - } + if (( vol = getvolbyvid( vid )) == NULL ) { + return( AFPERR_PARAM); + } - if (vol->v_flags & AFPVOL_RO) - return AFPERR_VLOCK; + if (vol->v_flags & AFPVOL_RO) + return AFPERR_VLOCK; - /* source and destination dids */ - memcpy(&sid, ibuf, sizeof(sid)); - ibuf += sizeof(sid); - memcpy(&did, ibuf, sizeof(did)); - ibuf += sizeof(did); + /* source and destination dids */ + memcpy(&sid, ibuf, sizeof(sid)); + ibuf += sizeof(sid); + memcpy(&did, ibuf, sizeof(did)); + ibuf += sizeof(did); - /* source file */ - if ((dir = dirsearch( vol, sid )) == NULL ) { - return( AFPERR_PARAM ); - } + /* source file */ + if ((dir = dirlookup( vol, sid )) == NULL ) { + return( AFPERR_PARAM ); + } - if (( path = cname( vol, dir, &ibuf )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( path = cname( vol, dir, &ibuf )) == NULL ) { + return( AFPERR_PARAM ); + } - if ( *path == '\0' ) { - return( AFPERR_BADTYPE ); - } + if ( *path == '\0' ) { + return( AFPERR_BADTYPE ); /* it's a dir */ + } - upath = mtoupath(vol, path); - if (stat(upath, &srcst) < 0) { - switch (errno) { - case ENOENT: - return AFPERR_NOID; - case EPERM: - case EACCES: - return AFPERR_ACCESS; - default: - return AFPERR_PARAM; - } + upath = mtoupath(vol, path); + if (stat(upath, &srcst) < 0) { + switch (errno) { + case ENOENT: + return AFPERR_NOID; + case EPERM: + case EACCES: + return AFPERR_ACCESS; + default: + return AFPERR_PARAM; } - - /* save some stuff */ - sdir = curdir; - spath = obj->oldtmp; - supath = obj->newtmp; - strcpy(spath, path); - strcpy(supath, upath); /* this is for the cnid changing */ - p = ctoupath( vol, sdir, spath); - - /* look for the source cnid. if it doesn't exist, don't worry about - * it. */ + } + memset(&ads, 0, sizeof(ads)); + adsp = &ads; + if ((s_of = of_findname(upath, &srcst))) { + /* reuse struct adouble so it won't break locks */ + adsp = s_of->of_ad; + } + /* save some stuff */ + sdir = curdir; + spath = obj->oldtmp; + supath = obj->newtmp; + strcpy(spath, path); + strcpy(supath, upath); /* this is for the cnid changing */ + p = ctoupath( vol, sdir, spath); + + /* look for the source cnid. if it doesn't exist, don't worry about + * it. */ #ifdef CNID_DB - sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath, - slen = strlen(supath)); + sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath, + slen = strlen(supath)); #endif /* CNID_DB */ - if (( dir = dirsearch( vol, did )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( dir = dirlookup( vol, did )) == NULL ) { + return( AFPERR_PARAM ); + } - if (( path = cname( vol, dir, &ibuf )) == NULL ) { - return( AFPERR_PARAM ); - } + if (( path = cname( vol, dir, &ibuf )) == NULL ) { + return( AFPERR_PARAM ); + } - if ( *path == '\0' ) { - return( AFPERR_BADTYPE ); - } + if ( *path == '\0' ) { + return( AFPERR_BADTYPE ); + } - /* FPExchangeFiles is the only call that can return the SameObj - * error */ - if ((curdir == sdir) && strcmp(spath, path) == 0) - return AFPERR_SAMEOBJ; + /* FPExchangeFiles is the only call that can return the SameObj + * error */ + if ((curdir == sdir) && strcmp(spath, path) == 0) + return AFPERR_SAMEOBJ; - upath = mtoupath(vol, path); - if (stat(upath, &destst) < 0) { - switch (errno) { - case ENOENT: - return AFPERR_NOID; - case EPERM: - case EACCES: - return AFPERR_ACCESS; - default: - return AFPERR_PARAM; - } + upath = mtoupath(vol, path); + if (stat(upath, &destst) < 0) { + switch (errno) { + case ENOENT: + return AFPERR_NOID; + case EPERM: + case EACCES: + return AFPERR_ACCESS; + default: + return AFPERR_PARAM; } + } + memset(&add, 0, sizeof(add)); + addp = &add; + if ((d_of = of_findname( upath, &destst))) { + /* reuse struct adouble so it won't break locks */ + addp = d_of->of_ad; + } + /* they are not on the same device and at least one is open + */ + if ((d_of || s_of) && srcst.st_dev != destst.st_dev) + return AFPERR_MISC; + #ifdef CNID_DB - /* look for destination id. */ - did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath, - dlen = strlen(upath)); + /* look for destination id. */ + did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath, + dlen = strlen(upath)); #endif /* CNID_DB */ - /* construct a temp name. - * NOTE: the temp file will be in the dest file's directory. it - * will also be inaccessible from AFP. */ - memcpy(temp, APPLETEMP, sizeof(APPLETEMP)); - if (!mktemp(temp)) - return AFPERR_MISC; + /* construct a temp name. + * NOTE: the temp file will be in the dest file's directory. it + * will also be inaccessible from AFP. */ + memcpy(temp, APPLETEMP, sizeof(APPLETEMP)); + if (!mktemp(temp)) + return AFPERR_MISC; - /* now, quickly rename the file. we error if we can't. */ - if ((err = renamefile(p, temp, temp, vol_noadouble(vol))) < 0) - goto err_exchangefile; - of_rename(vol, sdir, spath, curdir, temp); + /* now, quickly rename the file. we error if we can't. */ + if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0) + goto err_exchangefile; + of_rename(vol, s_of, sdir, spath, curdir, temp); - /* rename destination to source */ - if ((err = renamefile(path, p, spath, vol_noadouble(vol))) < 0) - goto err_src_to_tmp; - of_rename(vol, curdir, path, sdir, spath); + /* rename destination to source */ + if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0) + goto err_src_to_tmp; + of_rename(vol, d_of, curdir, path, sdir, spath); - /* rename temp to destination */ - if ((err = renamefile(temp, upath, path, vol_noadouble(vol))) < 0) - goto err_dest_to_src; - of_rename(vol, curdir, temp, curdir, path); + /* rename temp to destination */ + if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0) + goto err_dest_to_src; + of_rename(vol, s_of, curdir, temp, curdir, path); #ifdef CNID_DB - /* id's need switching. src -> dest and dest -> src. */ - if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did, - upath, dlen) < 0)) { - switch (errno) { - case EPERM: - case EACCES: - err = AFPERR_ACCESS; - break; - default: - err = AFPERR_PARAM; - } - goto err_temp_to_dest; + /* id's need switching. src -> dest and dest -> src. */ + if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did, + upath, dlen) < 0)) { + switch (errno) { + case EPERM: + case EACCES: + err = AFPERR_ACCESS; + break; + default: + err = AFPERR_PARAM; } + goto err_temp_to_dest; + } - if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did, - supath, slen) < 0)) { - switch (errno) { - case EPERM: - case EACCES: - err = AFPERR_ACCESS; - break; - default: - err = AFPERR_PARAM; - } - - if (sid) - cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen); - goto err_temp_to_dest; + if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did, + supath, slen) < 0)) { + switch (errno) { + case EPERM: + case EACCES: + err = AFPERR_ACCESS; + break; + default: + err = AFPERR_PARAM; } + + if (sid) + cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen); + goto err_temp_to_dest; + } #endif /* CNID_DB */ #ifdef DEBUG - LOG(log_info, logtype_default, "ending afp_exchangefiles:"); + LOG(log_info, logtype_afpd, "ending afp_exchangefiles:"); #endif /* DEBUG */ - return AFP_OK; + return AFP_OK; - /* all this stuff is so that we can unwind a failed operation - * properly. */ + /* all this stuff is so that we can unwind a failed operation + * properly. */ +#ifdef CNID_DB err_temp_to_dest: - /* rename dest to temp */ - renamefile(upath, temp, temp, vol_noadouble(vol)); - of_rename(vol, curdir, upath, curdir, temp); +#endif + /* rename dest to temp */ + renamefile(upath, temp, temp, vol_noadouble(vol), adsp); + of_rename(vol, s_of, curdir, upath, curdir, temp); err_dest_to_src: - /* rename source back to dest */ - renamefile(p, upath, path, vol_noadouble(vol)); - of_rename(vol, sdir, spath, curdir, path); + /* rename source back to dest */ + renamefile(p, upath, path, vol_noadouble(vol), addp); + of_rename(vol, d_of, sdir, spath, curdir, path); err_src_to_tmp: - /* rename temp back to source */ - renamefile(temp, p, spath, vol_noadouble(vol)); - of_rename(vol, curdir, temp, sdir, spath); + /* rename temp back to source */ + renamefile(temp, p, spath, vol_noadouble(vol), adsp); + of_rename(vol, s_of, curdir, temp, sdir, spath); err_exchangefile: - return err; - } + return err; +}