/*
- * $Id: file.c,v 1.79 2003-01-26 10:42:40 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.
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;
}
}
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;
}
else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
err = netatalk_unlink( file );
}
-
- 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:");