/*
- * $Id: file.c,v 1.76 2003-01-21 10:09:13 didg Exp $
+ * $Id: file.c,v 1.83 2003-02-04 18:26:20 didg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
memcpy(&did, ibuf, sizeof( did ));
ibuf += sizeof( did );
if (NULL == ( dir = dirlookup( vol, did )) ) {
- return( AFPERR_NOOBJ );
+ return afp_errno; /* was AFPERR_NOOBJ */
}
memcpy(&bitmap, ibuf, sizeof( bitmap ));
return afp_errno;
}
- if ( *s_path->m_name == '\0' ) {
+ if (path_isadir(s_path)) {
return( AFPERR_BADTYPE ); /* it's a directory */
}
return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
}
isad = 0;
- } else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
+ } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
ad_setentrylen( adp, ADEID_NAME, strlen( path->m_name ));
memcpy(ad_entry( adp, ADEID_NAME ), path->m_name,
ad_getentrylen( adp, ADEID_NAME ));
/*
* renamefile and copyfile take the old and new unix pathnames
* and the new mac name.
- * NOTE: if we have to copy a file instead of renaming it, locks
- * will break. Anyway it's an error because then we have 2 files.
*
* src the source path
* dst the dest filename in current dir
const int noadouble;
struct adouble *adp;
{
- char adsrc[ MAXPATHLEN + 1];
- int len, rc;
-
- /*
- * Note that this is only checking the existance of the data file,
- * not the header file. The thinking is that if the data file doesn't
- * exist, but the header file does, the right thing to do is remove
- * the data file silently.
- */
-
- /* existence check moved to afp_moveandrename */
+ char adsrc[ MAXPATHLEN + 1];
+ int len;
+ int rc;
#ifdef DEBUG
LOG(log_info, logtype_afpd, "begin renamefile:");
case EROFS:
return AFPERR_VLOCK;
case EXDEV : /* Cross device move -- try copy */
+ /* NOTE: with open file it's an error because after the copy we will
+ * get two files, it's fixable for our process (eg reopen the new file, get the
+ * locks, and so on. But it doesn't solve the case with a second process
+ */
+ if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
+ /* FIXME warning in syslog so admin'd know there's a conflict ?*/
+ return AFPERR_OLOCK; /* little lie */
+ }
if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
deletefile( dst, 0 );
return( rc );
}
strcpy( adsrc, ad_path( src, 0 ));
- rc = 0;
-rename_retry:
+
if (unix_rename( adsrc, ad_path( dst, 0 )) < 0 ) {
struct stat st;
+ int err;
+
+ err = errno;
+ if (errno == ENOENT) {
+ struct adouble ad;
- switch ( errno ) {
- case ENOENT :
- /* check for a source appledouble header. if it exists, make
- * a dest appledouble directory and do the rename again. */
- if (rc || stat(adsrc, &st) ||
- (ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
+ if (stat(adsrc, &st)) /* source has no ressource fork, */
return AFP_OK;
- rc++;
- ad_close(adp, ADFLAGS_HF);
- goto rename_retry;
- case EPERM:
- case EACCES :
- return( AFPERR_ACCESS );
- case EROFS:
- return AFPERR_VLOCK;
- default :
- return( AFPERR_PARAM );
+
+ /* We are here because :
+ * -there's no dest folder.
+ * -there's no .AppleDouble in the dest folder.
+ * if we use the struct adouble passed in parameter it will not
+ * create .AppleDouble if the file is already opened, so we
+ * use a diff one, it's not a pb,ie it's not the same file, yet.
+ */
+ memset(&ad, 0, sizeof(ad));
+ if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
+ ad_close(&ad, ADFLAGS_HF);
+ if (!unix_rename( adsrc, ad_path( dst, 0 )) )
+ err = 0;
+ else
+ err = errno;
+ }
+ else { /* it's something else, bail out */
+ err = errno;
+ }
+ }
+ /* try to undo the data fork rename,
+ * we know we are on the same device
+ */
+ if (err) {
+ unix_rename( dst, src );
+ /* return the first error */
+ switch ( err) {
+ case ENOENT :
+ return AFPERR_NOOBJ;
+ case EPERM:
+ case EACCES :
+ return AFPERR_ACCESS ;
+ case EROFS:
+ return AFPERR_VLOCK;
+ default :
+ return AFPERR_PARAM ;
+ }
}
}
- if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
- switch ( errno ) {
- case ENOENT :
- return( AFPERR_NOOBJ );
- case EACCES :
- return( AFPERR_ACCESS );
- case EROFS:
- return AFPERR_VLOCK;
- default :
- return( AFPERR_PARAM );
- }
+ /* don't care if we can't open the newly renamed ressource fork
+ */
+ if ( !ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
+ len = strlen( newname );
+ ad_setentrylen( adp, ADEID_NAME, len );
+ memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
+ ad_flush( adp, ADFLAGS_HF );
+ ad_close( adp, ADFLAGS_HF );
}
-
- len = strlen( newname );
- ad_setentrylen( adp, ADEID_NAME, len );
- memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
- ad_flush( adp, ADFLAGS_HF );
- ad_close( adp, ADFLAGS_HF );
-
#ifdef DEBUG
LOG(log_info, logtype_afpd, "end renamefile:");
#endif /* DEBUG */
if (plen) {
strncpy( newname, ibuf, plen );
newname[ plen ] = '\0';
- if (strchr(newname,'/')) {
+ if (strlen(newname) != plen) {
return -1;
}
}
if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
return afp_errno;
}
- if ( *s_path->m_name == '\0' ) {
+ if ( path_isadir(s_path) ) {
return( AFPERR_BADTYPE );
}
return AFPERR_DENYCONF;
p = ctoupath( vol, curdir, newname );
+ if (!p) {
+ return AFPERR_PARAM;
+
+ }
#ifdef FORCE_UIDGID
/* FIXME svid != dvid && dvid's user can't read svid */
#endif
return afp_errno;
}
if ( *s_path->m_name != '\0' ) {
- return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
+ return (path_isadir( s_path))? AFPERR_PARAM:AFPERR_BADTYPE ;
}
/* one of the handful of places that knows about the path type */
when deletefile is called we don't have lock on it, file is closed (for us)
untrue if called by renamefile
+
+ ad_open always try to open file RDWR first and ad_lock takes care of
+ WRITE lock on read only file.
*/
int deletefile( file, checkAttrib )
char *file;
{
struct adouble ad;
int adflags, err = AFP_OK;
- int locktype = ADLOCK_WR;
- int openmode = O_RDWR;
#ifdef DEBUG
LOG(log_info, logtype_afpd, "begin deletefile:");
#endif /* DEBUG */
+ /* try to open both forks at once */
+ adflags = ADFLAGS_DF|ADFLAGS_HF;
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 ) {
+ if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
switch (errno) {
case ENOENT:
- adflags = ADFLAGS_DF;
+ if (adflags == ADFLAGS_DF)
+ return AFPERR_NOOBJ;
+
/* 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;
+ adflags = ADFLAGS_DF;
+ continue;
case EACCES:
- if(openmode == O_RDWR) {
- openmode = O_RDONLY;
- locktype = ADLOCK_RD;
- continue;
- } else {
- return AFPERR_ACCESS;
- }
+ return AFPERR_ACCESS;
case EROFS:
return AFPERR_VLOCK;
default:
* 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
+ * FIXME it doesn't work for RFORK open read only and fork open without deny mode
*/
- if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
+ if (ad_tmplock(&ad, ADEID_RFORK, ADLOCK_WR |ADLOCK_FILELOCK, 0, 0, 0) < 0 ) {
ad_close( &ad, adflags );
return( AFPERR_BUSY );
}
}
- if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0, 0 ) < 0) {
+ if (ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 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;
- }
+ else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
+ err = netatalk_unlink( file );
}
-
- 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 |ADLOCK_FILELOCK, 0, 0, 0);
- ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0, 0);
- ad_close( &ad, adflags );
+ ad_close( &ad, adflags ); /* ad_close removes locks if any */
#ifdef DEBUG
LOG(log_info, logtype_afpd, "end deletefile:");
}
if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
- return( AFPERR_PARAM );
+ return afp_errno; /* was AFPERR_PARAM */
}
- if ( *s_path->m_name == '\0' ) {
+ if ( path_isadir(s_path) ) {
return( AFPERR_BADTYPE );
}
struct adouble *addp;
struct ofork *s_of;
struct ofork *d_of;
+ int crossdev;
#ifdef CNID_DB
int slen, dlen;
}
if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
- return( AFPERR_PARAM );
+ return afp_errno; /* was AFPERR_PARAM */
}
- if ( *path->m_name == '\0' ) {
+ if ( path_isadir(path) ) {
return( AFPERR_BADTYPE ); /* it's a dir */
}
strcpy(spath, path->m_name);
strcpy(supath, upath); /* this is for the cnid changing */
p = absupath( vol, sdir, upath);
+ if (!p) {
+ /* pathname too long */
+ return AFPERR_PARAM ;
+ }
/* look for the source cnid. if it doesn't exist, don't worry about
* it. */
return( AFPERR_PARAM );
}
- if ( *path->m_name == '\0' ) {
+ if ( path_isadir(path) ) {
return( AFPERR_BADTYPE );
}
* error */
if ((curdir == sdir) && strcmp(spath, path->m_name) == 0)
return AFPERR_SAMEOBJ;
- memcpy(&srcst, &path->st, sizeof(struct stat));
- switch (errno) {
+ switch (path->st_errno) {
case 0:
break;
case ENOENT:
/* they are not on the same device and at least one is open
*/
- if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
+ crossdev = (srcst.st_dev != destst.st_dev);
+ if ((d_of || s_of) && crossdev)
return AFPERR_MISC;
upath = path->u_name;
of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
#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.
+ * we need to re-stat() if it was a cross device copy.
+ */
+ if (sid) {
+ cnid_delete(vol->v_db, sid);
}
-
- if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
- supath, slen) < 0)) {
+ if (did) {
+ cnid_delete(vol->v_db, did);
+ }
+ if ((did && ( (crossdev && stat( upath, &srcst) < 0) ||
+ cnid_update(vol->v_db, did, &srcst, curdir->d_did,upath, dlen) < 0))
+ ||
+ (sid && ( (crossdev && stat(p, &destst) < 0) ||
+ cnid_update(vol->v_db, sid, &destst, sdir->d_did,supath, slen) < 0))
+ ) {
switch (errno) {
case EPERM:
case EACCES:
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 */