From 96afda34736f3aee95560c125e59211ab811e203 Mon Sep 17 00:00:00 2001 From: didg Date: Fri, 29 Sep 2006 09:39:16 +0000 Subject: [PATCH] add a SFM compatible format for adouble --- bin/megatron/nad.c | 10 +- etc/afpd/desktop.c | 8 +- etc/afpd/directory.c | 8 +- etc/afpd/file.c | 168 ++++++------- etc/afpd/file.h | 7 +- etc/afpd/fork.c | 57 ++--- etc/afpd/ofork.c | 8 +- etc/afpd/vfs_adouble.c | 21 ++ etc/afpd/volume.c | 15 +- include/atalk/adouble.h | 73 ++++-- libatalk/adouble/ad_attr.c | 11 +- libatalk/adouble/ad_date.c | 8 +- libatalk/adouble/ad_flush.c | 133 ++++++++-- libatalk/adouble/ad_lock.c | 57 +++-- libatalk/adouble/ad_open.c | 471 ++++++++++++++++++++++++++++++------ libatalk/adouble/ad_read.c | 10 +- libatalk/adouble/ad_size.c | 4 +- libatalk/adouble/ad_write.c | 14 +- 18 files changed, 797 insertions(+), 286 deletions(-) diff --git a/bin/megatron/nad.c b/bin/megatron/nad.c index 2b1c14c8..f9aab5d5 100644 --- a/bin/megatron/nad.c +++ b/bin/megatron/nad.c @@ -1,5 +1,5 @@ /* - * $Id: nad.c,v 1.14 2006-09-19 01:35:45 didg Exp $ + * $Id: nad.c,v 1.15 2006-09-29 09:39:16 didg Exp $ */ #ifdef HAVE_CONFIG_H @@ -451,7 +451,7 @@ int nad_open( path, openflags, fh, options ) initvol(path); strcpy( nad.adpath[0], path ); strcpy( nad.adpath[1], - nad.ad.ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF )); + nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF )); for ( fork = 0 ; fork < NUMFORKS ; fork++ ) { if ( stat( nad.adpath[ fork ], &st ) < 0 ) { if ( errno == ENOENT ) { @@ -479,7 +479,7 @@ int nad_open( path, openflags, fh, options ) strcpy( nad.macname, fh->name ); strcpy( nad.adpath[0], mtoupath( nad.macname )); strcpy( nad.adpath[1], - nad.ad.ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF )); + nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF )); #if DEBUG fprintf(stderr, "%s\n", nad.macname); fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]); @@ -691,7 +691,7 @@ int nad_header_write( fh ) #endif /* HEXOUTPUT */ nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0; - ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF ); + ad_flush( &nad.ad ); return( 0 ); } @@ -763,7 +763,7 @@ int status; { int rv; if ( status == KEEP ) { - if (( rv = ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) { + if (( rv = ad_flush( &nad.ad )) < 0 ) { fprintf( stderr, "nad_close rv for flush %d\n", rv ); return( rv ); } diff --git a/etc/afpd/desktop.c b/etc/afpd/desktop.c index dcefcc84..927be9d4 100644 --- a/etc/afpd/desktop.c +++ b/etc/afpd/desktop.c @@ -1,5 +1,5 @@ /* - * $Id: desktop.c,v 1.36 2006-09-19 01:35:45 didg Exp $ + * $Id: desktop.c,v 1.37 2006-09-29 09:39:16 didg Exp $ * * See COPYRIGHT. * @@ -748,7 +748,7 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf) } if (ad_getentryoff(adp, ADEID_COMMENT)) { - if ( (ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) { + if ( (ad_get_MD_flags( adp ) & O_CREAT) ) { if ( *path->m_name == '\0' ) { name = curdir->d_m_name; } else { @@ -758,7 +758,7 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf) } ad_setentrylen( adp, ADEID_COMMENT, clen ); memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen ); - ad_flush_metadata( adp ); + ad_flush( adp ); } ad_close_metadata( adp); return( AFP_OK ); @@ -912,7 +912,7 @@ static int ad_rmvcomment(struct vol *vol, struct path *path) if (ad_getentryoff(adp, ADEID_COMMENT)) { ad_setentrylen( adp, ADEID_COMMENT, 0 ); - ad_flush_metadata( adp ); + ad_flush( adp ); } ad_close_metadata( adp); return( AFP_OK ); diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 224f3979..b9c68774 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,5 +1,5 @@ /* - * $Id: directory.c,v 1.83 2006-09-19 23:00:49 didg Exp $ + * $Id: directory.c,v 1.84 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -2253,7 +2253,7 @@ setdirparam_done: ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp); } } - ad_flush_metadata( &ad); + ad_flush( &ad); ad_close_metadata( &ad); } @@ -2344,7 +2344,7 @@ int ibuflen _U_, *rbuflen; ad_setname(&ad, s_path->m_name); ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp); - ad_flush_metadata( &ad); + ad_flush( &ad); ad_close_metadata( &ad); createdir_done: @@ -2408,7 +2408,7 @@ struct dir *dir, *newparent; if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) { ad_setname(&ad, newname); - ad_flush_metadata( &ad); + ad_flush( &ad); ad_close_metadata( &ad); } diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 523cda41..e091ba0f 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,5 +1,5 @@ /* - * $Id: file.c,v 1.102 2006-09-19 23:00:49 didg Exp $ + * $Id: file.c,v 1.103 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -227,7 +227,7 @@ u_int32_t aint = 0; * for a folder adp is always null */ if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) { - ad_flush(adp, ADFLAGS_HF); + ad_flush(adp); } } #endif @@ -239,7 +239,7 @@ u_int32_t aint = 0; int getmetadata(struct vol *vol, u_int16_t bitmap, struct path *path, struct dir *dir, - char *buf, int *buflen, struct adouble *adp, int attrbits ) + char *buf, int *buflen, struct adouble *adp) { char *data, *l_nameoff = NULL, *upath; char *utf_nameoff = NULL; @@ -296,12 +296,10 @@ int getmetadata(struct vol *vol, if ((ma.ma_user & AR_UWRITE)) { accessmode( upath, &ma, dir , st); if (!(ma.ma_user & AR_UWRITE)) { - attrbits |= ATTRBIT_NOWRITE; + ashort |= htons(ATTRBIT_NOWRITE); } } #endif - if (attrbits) - ashort = htons(ntohs(ashort) | attrbits); memcpy(data, &ashort, sizeof( ashort )); data += sizeof( ashort ); break; @@ -518,7 +516,6 @@ int getfilparams(struct vol *vol, struct adouble ad, *adp; struct ofork *of; char *upath; - u_int16_t attrbits = 0; int opened = 0; int rc; @@ -528,18 +525,18 @@ int getfilparams(struct vol *vol, opened = PARAM_NEED_ADP(bitmap); adp = NULL; + if (opened) { + int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0; upath = path->u_name; if ((of = of_findname(path))) { 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 { ad_init(&ad, vol->v_adouble, vol->v_ad_options); adp = &ad; } - if ( ad_metadata( upath, 0, adp) < 0 ) { + if ( ad_metadata( upath, flags, adp) < 0 ) { switch (errno) { case EACCES: LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?", @@ -554,26 +551,8 @@ int getfilparams(struct vol *vol, break; } } - if (adp) { - /* 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)) { - attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0; - attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0; - } - if (!(attrbits & ATTRBIT_DOPEN)) { - attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0; - attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0; - } - } - } } - rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits); + rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp); if ( adp ) { ad_close_metadata( adp); } @@ -677,7 +656,7 @@ int ibuflen _U_, *rbuflen; return( AFPERR_PARAM ); } } - if ( ad_hfileno( adp ) == -1 ) { + if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */ /* on noadouble volumes, just creating the data fork is ok */ if (vol_noadouble(vol)) { ad_close( adp, ADFLAGS_DF ); @@ -693,7 +672,7 @@ int ibuflen _U_, *rbuflen; path = s_path->m_name; ad_setname(adp, path); - ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF ); + ad_flush( adp); ad_close( adp, ADFLAGS_DF|ADFLAGS_HF ); createfile_done: @@ -998,7 +977,7 @@ setfilparam_done: } if (isad) { - ad_flush_metadata( adp); + ad_flush( adp); ad_close_metadata( adp); } @@ -1050,7 +1029,7 @@ struct adouble *adp; * 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) { + if (adp->ad_open_forks) { /* FIXME warning in syslog so admin'd know there's a conflict ?*/ return AFPERR_OLOCK; /* little lie */ } @@ -1092,7 +1071,7 @@ struct adouble *adp; */ if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) { ad_setname(adp, newname); - ad_flush( adp, ADFLAGS_HF ); + ad_flush( adp ); ad_close( adp, ADFLAGS_HF ); } #ifdef DEBUG @@ -1326,13 +1305,31 @@ static __inline__ int copy_all(const int dfd, const void *buf, return 0; } -/* -------------------------- */ -static int copy_fd(int dfd, int sfd) +/* -------------------------- + * copy only the fork data stream +*/ +static int copy_fork(int eid, struct adouble *add, struct adouble *ads) { ssize_t cc; int err = 0; char filebuf[8192]; + int sfd, dfd; + if (eid == ADEID_DFORK) { + sfd = ad_data_fileno(ads); + dfd = ad_data_fileno(add); + } + else { + sfd = ad_reso_fileno(ads); + dfd = ad_reso_fileno(add); + } + + if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET)) + return -1; + + if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET)) + return -1; + #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */ /* doesn't work With 2.6 FIXME, only check for EBADFD ? */ off_t offset = 0; @@ -1378,7 +1375,7 @@ static int copy_fd(int dfd, int sfd) } /* ---------------------------------- - * if newname is NULL (from directory.c) we don't want to copy ressource fork. + * if newname is NULL (from directory.c) we don't want to copy the resource fork. * because we are doing it elsewhere. * currently if newname is NULL then adp is NULL. */ @@ -1414,12 +1411,12 @@ struct adouble *adp; goto done; } - if (ad_hfileno(adp) == -1) { + if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */ /* no resource fork, don't create one for dst file */ adflags &= ~ADFLAGS_HF; } - stat_result = fstat(ad_dfileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */ + stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */ if (stat_result < 0) { /* unlikely but if fstat fails, the default file mode will be 0666. */ @@ -1437,39 +1434,26 @@ struct adouble *adp; } /* XXX if the source and the dest don't use the same resource type it's broken */ - if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){ + if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){ /* copy the data fork */ - err = copy_fd(ad_dfileno(&add), ad_dfileno(adp)); + err = copy_fork(ADEID_DFORK, &add, adp); } - /* Now, reopen destination file */ if (err < 0) { ret_err = errno; } - ad_close( adp, adflags ); - - if (ad_close( &add, adflags ) <0) { - if (!ret_err) { - ret_err = errno; - } - deletefile(d_vol, dst, 0); - goto done; - } if (!ret_err && newname && (adflags & ADFLAGS_HF)) { /* set the new name in the resource fork */ - ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options); - if (ad_open_metadata(dst , noadouble, 0, &add) < 0) { - ret_err = errno; - } - else { - ad_setname(&add, newname); - ad_flush_metadata( &add); - if (ad_close_metadata( &add)) { - ret_err = errno; - } - } + ad_copy_header(&add, adp); + ad_setname(&add, newname); + ad_flush( &add ); } + ad_close( adp, adflags ); + + if (ad_close( &add, adflags ) <0) { + ret_err = errno; + } if (ret_err) { deletefile(d_vol, dst, 0); @@ -1518,6 +1502,24 @@ done: ad_open always try to open file RDWR first and ad_lock takes care of WRITE lock on read only file. */ + +static int check_attrib(struct adouble *adp) +{ +u_int16_t bshort = 0; + + ad_getattr(adp, &bshort); + /* + * Does kFPDeleteInhibitBit (bit 8) set? + */ + if ((bshort & htons(ATTRBIT_NODELETE))) { + return AFPERR_OLOCK; + } + if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) { + return AFPERR_BUSY; + } + return 0; +} + int deletefile( vol, file, checkAttrib ) const struct vol *vol; char *file; @@ -1533,8 +1535,19 @@ int checkAttrib; /* try to open both forks at once */ adflags = ADFLAGS_DF|ADFLAGS_HF; - ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */ + if (checkAttrib) { + /* was EACCESS error try to get only metadata */ + ad_init(&ad, vol->v_adouble, vol->v_ad_options); + if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) { + ad_close( &ad, adflags ); + if ((err = check_attrib(&ad))) { + return err; + } + } + } + while(1) { + ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */ if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) { switch (errno) { case ENOENT: @@ -1556,21 +1569,7 @@ int checkAttrib; } break; /* from the while */ } - /* - * Does kFPDeleteInhibitBit (bit 8) set? - */ - if (checkAttrib) { - u_int16_t bshort; - - if ( ad_metadata( file , 0, &ad) == 0 ) { - ad_getattr(&ad, &bshort); - ad_close_metadata( &ad); - if ((bshort & htons(ATTRBIT_NODELETE))) { - return AFPERR_OLOCK; - } - } - } - + if (adp && (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 @@ -1727,7 +1726,7 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data) return 0; } if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) { - ad_flush_metadata(adp); + ad_flush(adp); } ad_close_metadata(adp); } @@ -2009,7 +2008,8 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct } else { ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp); - if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) { + /* META and HF */ + if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) { /* from AFP spec. * The user must have the Read & Write privilege for both files in order to use this command. */ @@ -2212,12 +2212,12 @@ int ibuflen _U_, *rbuflen; /* here we need to reopen if crossdev */ if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp)) { - ad_flush( addp, ADFLAGS_HF ); + ad_flush( addp ); } if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino, did, curdir->d_did, vol->v_stamp)) { - ad_flush( adsp, ADFLAGS_HF ); + ad_flush( adsp ); } /* change perms, src gets dest perm and vice versa */ @@ -2282,10 +2282,10 @@ err_src_to_tmp: of_rename(vol, s_of, curdir, temp, sdir, spath); err_exchangefile: - if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) { + if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */ ad_close(adsp, ADFLAGS_HF); } - if ( !d_of && addp && ad_hfileno(addp) != -1 ) { + if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */ ad_close(addp, ADFLAGS_HF); } diff --git a/etc/afpd/file.h b/etc/afpd/file.h index dba23950..06fe64be 100644 --- a/etc/afpd/file.h +++ b/etc/afpd/file.h @@ -1,5 +1,5 @@ /* - * $Id: file.h,v 1.19 2006-09-19 23:00:50 didg Exp $ + * $Id: file.h,v 1.20 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -58,8 +58,13 @@ extern const u_char ufinderi[]; #define ATTRBIT_INVISIBLE (1<<0) /* invisible (d) */ #define ATTRBIT_MULTIUSER (1<<1) /* multiuser */ #define ATTRBIT_SYSTEM (1<<2) /* system (d) */ + +#if 0 +/* define in adouble.h */ #define ATTRBIT_DOPEN (1<<3) /* data fork already open */ #define ATTRBIT_ROPEN (1<<4) /* resource fork already open */ +#endif + #define ATTRBIT_SHARED (1<<4) /* shared area (d) */ #define ATTRBIT_NOWRITE (1<<5) /* write inhibit(v2)/read-only(v1) bit */ #define ATTRBIT_BACKUP (1<<6) /* backup needed (d) */ diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 1df39a0f..09b8ed52 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -1,5 +1,5 @@ /* - * $Id: fork.c,v 1.55 2005-09-28 09:46:37 didg Exp $ + * $Id: fork.c,v 1.56 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -48,14 +48,13 @@ 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 ); + int *buflen, struct adouble *adp); -static int getforkparams(ofork, bitmap, buf, buflen, attrbits ) +static int getforkparams(ofork, bitmap, buf, buflen ) struct ofork *ofork; u_int16_t bitmap; char *buf; int *buflen; -const u_int16_t attrbits; { struct path path; struct stat *st; @@ -74,7 +73,7 @@ const u_int16_t attrbits; return( AFPERR_BITMAP ); } - if ( ad_hfileno( ofork->of_ad ) == -1 ) { + if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */ adp = NULL; } else { adp = ofork->of_ad; @@ -91,18 +90,18 @@ const u_int16_t attrbits; if ( bitmap & ( (1<of_ad ) == -1 ) { + if ( ad_data_fileno( ofork->of_ad ) == -1 ) { if (movecwd(vol, dir) < 0) return( AFPERR_NOOBJ ); if ( stat( 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(vol, bitmap, &path, dir, buf, buflen, adp ); } /* ---------------------------- */ @@ -269,7 +268,7 @@ int ibuflen _U_, *rbuflen; struct adouble *adsame = NULL; int buflen, ret, adflags, eid; u_int32_t did; - u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0; + u_int16_t vid, bitmap, access, ofrefnum; char fork, *path, *upath; struct stat *st; u_int16_t bshort; @@ -346,9 +345,6 @@ int ibuflen _U_, *rbuflen; 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); - adsame = opened->of_ad; } @@ -462,12 +458,12 @@ int ibuflen _U_, *rbuflen; if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) { if (ad_setname(ofork->of_ad, path)) { - ad_flush( ofork->of_ad, adflags ); + ad_flush( ofork->of_ad ); } } if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ), - &buflen, attrbits )) != AFP_OK ) { + &buflen )) != AFP_OK ) { ad_close( ofork->of_ad, adflags ); goto openfork_err; } @@ -480,7 +476,7 @@ int ibuflen _U_, *rbuflen; /* check WriteInhibit bit if we have a ressource fork * 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 ); @@ -496,7 +492,7 @@ int ibuflen _U_, *rbuflen; */ /* don't try to lock non-existent rforks. */ - if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) { + if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */ ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum); /* can we access the fork? */ @@ -629,7 +625,7 @@ int ibuflen, *rbuflen; if (err < 0) goto afp_setfork_err; - if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) { + 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; } @@ -717,7 +713,7 @@ int is64; 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 >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/ return AFPERR_LOCK; } @@ -783,7 +779,7 @@ struct ofork *of; { struct extmap *em; - if ( ad_hfileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { + if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */ /* no resource fork or no finderinfo, use our files extension mapping */ if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) { return 0; @@ -1110,14 +1106,14 @@ struct ofork *ofork; int err = 0, doflush = 0; - if ( ad_dfileno( ofork->of_ad ) != -1 && - fsync( ad_dfileno( ofork->of_ad )) < 0 ) { + if ( ad_data_fileno( ofork->of_ad ) != -1 && + fsync( ad_data_fileno( ofork->of_ad )) < 0 ) { LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s", - of_name(ofork), ad_dfileno(ofork->of_ad), strerror(errno) ); + of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) ); err = -1; } - if ( ad_hfileno( ofork->of_ad ) != -1 && + if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */ (ofork->of_flags & AFPFORK_RSRC)) { /* read in the rfork length */ @@ -1131,15 +1127,15 @@ struct ofork *ofork; } /* flush the header */ - if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0) + 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(%s): hfile(%d) %s", - of_name(ofork), ad_hfileno(ofork->of_ad), strerror(errno) ); + of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) ); } return( err ); @@ -1375,7 +1371,7 @@ int is64; } ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); - if ( ad_hfileno( ofork->of_ad ) != -1 ) + if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */ ofork->of_flags |= AFPFORK_DIRTY; *rbuflen = set_off_t (offset, rbuf, is64); @@ -1421,7 +1417,6 @@ int ibuflen _U_, *rbuflen; struct ofork *ofork; int buflen, ret; u_int16_t ofrefnum, bitmap; - u_int16_t attrbits = 0; ibuf += 2; memcpy(&ofrefnum, ibuf, sizeof( ofrefnum )); @@ -1435,10 +1430,8 @@ int ibuflen _U_, *rbuflen; 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_meta_fileno( ofork->of_ad ) != -1 ) { /* META */ if ( ad_refresh( ofork->of_ad ) < 0 ) { LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) ); return( AFPERR_PARAM ); @@ -1446,7 +1439,7 @@ int ibuflen _U_, *rbuflen; } if (AFP_OK != ( ret = getforkparams( ofork, bitmap, - rbuf + sizeof( u_short ), &buflen, attrbits ))) { + rbuf + sizeof( u_short ), &buflen ))) { return( ret ); } diff --git a/etc/afpd/ofork.c b/etc/afpd/ofork.c index e4ec59b5..abf7b474 100644 --- a/etc/afpd/ofork.c +++ b/etc/afpd/ofork.c @@ -1,5 +1,5 @@ /* - * $Id: ofork.c,v 1.24 2005-09-28 09:46:37 didg Exp $ + * $Id: ofork.c,v 1.25 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1996 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -387,10 +387,10 @@ int of_closefork(struct ofork *ofork) int ret; adflags = 0; - if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) { + if ((ofork->of_flags & AFPFORK_DATA) && (ad_data_fileno( ofork->of_ad ) != -1)) { adflags |= ADFLAGS_DF; } - if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) { + if ( (ofork->of_flags & AFPFORK_OPEN) && ad_reso_fileno( ofork->of_ad ) != -1 ) { adflags |= ADFLAGS_HF; /* * Only set the rfork's length if we're closing the rfork. @@ -402,7 +402,7 @@ int of_closefork(struct ofork *ofork) doflush++; } if ( doflush ) { - ad_flush( ofork->of_ad, adflags ); + ad_flush( ofork->of_ad ); } } } diff --git a/etc/afpd/vfs_adouble.c b/etc/afpd/vfs_adouble.c index 30d84c69..1fae02b0 100644 --- a/etc/afpd/vfs_adouble.c +++ b/etc/afpd/vfs_adouble.c @@ -742,6 +742,24 @@ struct vfs_ops netatalk_adouble_ads = { /* rf_renamefile: */ RF_renamefile_ads, }; +/* ======================================= + samba sfm format + ad_path shouldn't be set here + */ +struct vfs_ops netatalk_adouble_sfm = { + /* ad_path: */ ad_path_sfm, + /* validupath: */ validupath_adouble, + /* rf_chown: */ RF_chown_ads, + /* rf_renamedir: */ RF_renamedir_adouble, + /* rf_deletecurdir: */ RF_deletecurdir_ads, + /* rf_setfilmode: */ RF_setfilmode_ads, + /* rf_setdirmode: */ RF_setdirmode_ads, + /* rf_setdirunixmode:*/ RF_setdirunixmode_ads, + /* rf_setdirowner: */ RF_setdirowner_ads, + /* rf_deletefile: */ RF_deletefile_ads, + /* rf_renamefile: */ RF_renamefile_ads, +}; + /* ---------------- */ void initvol_vfs(struct vol *vol) { @@ -751,6 +769,9 @@ void initvol_vfs(struct vol *vol) else if (vol->v_adouble == AD_VERSION1_ADS) { vol->vfs = &netatalk_adouble_ads; } + else if (vol->v_adouble == AD_VERSION1_SFM) { + vol->vfs = &netatalk_adouble_sfm; + } else { vol->vfs = &netatalk_adouble; } diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 56a6d6fd..9c527245 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -1,5 +1,5 @@ /* - * $Id: volume.c,v 1.67 2006-09-19 23:00:50 didg Exp $ + * $Id: volume.c,v 1.68 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -436,6 +436,8 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX; else if (strcasecmp(val + 1, "ads") == 0) options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_ADS; + else if (strcasecmp(val + 1, "sfm") == 0) + options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_SFM; #endif } else if (optionok(tmp, "options:", val)) { char *p; @@ -1237,7 +1239,7 @@ int *buflen; isad = 0; vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime); - } else if (ad_get_HF_flags( &ad ) & O_CREAT) { + } else if (ad_get_MD_flags( &ad ) & O_CREAT) { slash = strrchr( vol->v_path, '/' ); if(slash) slash++; @@ -1249,7 +1251,7 @@ int *buflen; ad_getentrylen( &ad, ADEID_NAME )); } vol_setdate(vol->v_vid, &ad, st->st_mtime); - ad_flush_metadata(&ad); + ad_flush(&ad); } else { if (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0) @@ -2087,7 +2089,7 @@ int ibuflen _U_, *rbuflen; memcpy(&aint, ibuf, sizeof(aint)); ad_setdate(&ad, AD_DATE_BACKUP, aint); - ad_flush(&ad, ADFLAGS_HF); + ad_flush(&ad); ad_close(&ad, ADFLAGS_HF); return( AFP_OK ); } @@ -2198,7 +2200,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr)); } - ad_flush( &ad, ADFLAGS_HF ); + ad_flush( &ad ); ad_close( &ad, ADFLAGS_HF ); } free(p); @@ -2277,6 +2279,9 @@ static int savevoloptions (const struct vol *vol) case AD_VERSION1_ADS: strlcat(buf, "ADOUBLE_VER:ads\n", sizeof(buf)); break; + case AD_VERSION1_SFM: + strlcat(buf, "ADOUBLE_VER:sfm\n", sizeof(buf)); + break; } strlcat(buf, "CNIDBACKEND:", sizeof(buf)); diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index d71eb05a..17f02c53 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -1,5 +1,5 @@ /* - * $Id: adouble.h,v 1.30 2006-09-19 23:00:50 didg Exp $ + * $Id: adouble.h,v 1.31 2006-09-29 09:39:16 didg Exp $ * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. * @@ -80,9 +80,12 @@ /* version info */ #define AD_VERSION1 0x00010000 +#define SFM_VERSION AD_VERSION1 + #define AD_VERSION2 0x00020000 #define AD_VERSION2_OSX 0x00020001 #define AD_VERSION1_ADS 0x00010002 +#define AD_VERSION1_SFM 0x00010003 #define AD_VERSION AD_VERSION2 /* @@ -112,12 +115,14 @@ #define ADEID_PRIVINO 17 #define ADEID_PRIVSYN 18 /* in synch with database */ #define ADEID_PRIVID 19 +#define ADEID_SFMRESERVE1 20 +#define ADEID_SFMRESERVE2 21 #define AD_DEV 0x80444556 #define AD_INO 0x80494E4F #define AD_SYN 0x8053594E #define AD_ID 0x8053567E -#define ADEID_MAX 20 +#define ADEID_MAX 22 #endif /* magic */ @@ -125,6 +130,7 @@ #define AD_APPLEDOUBLE_MAGIC 0x00051607 #define AD_MAGIC AD_APPLEDOUBLE_MAGIC +#define SFM_MAGIC 0x00504641 /* sizes of relevant entry bits */ #define ADEDLEN_MAGIC 4 @@ -159,6 +165,10 @@ #define ADEID_NUM_V1 5 #define ADEID_NUM_V2 13 +// #define ADEID_NUM_SFM 5 +/* sizeof SFM meta data */ +#define AD_SFM_LEN 60 + /* 589 */ #define AD_DATASZ1 (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT +ADEDLEN_FILEI +ADEDLEN_FINDERI+\ ADEID_NUM_V1*AD_ENTRY_LEN) @@ -239,14 +249,22 @@ struct ad_fd { int adf_refcount, adf_lockcount, adf_lockmax; }; +/* fork attribute */ +#define ATTRBIT_DOPEN (1<<3) /* data fork already open */ +#define ATTRBIT_ROPEN (1<<4) /* resource fork already open */ + /* some header protection */ #define AD_INITED 0xad494e54 /* ad"INT" */ +struct adouble_fops; + struct adouble { u_int32_t ad_magic; u_int32_t ad_version; char ad_filler[ 16 ]; struct ad_entry ad_eid[ ADEID_MAX ]; - struct ad_fd ad_df, ad_hf; + struct ad_fd ad_data_fork, ad_resource_fork, ad_metadata_fork; + struct ad_fd *ad_md; /* either ad_resource or ad_metadata */ + int ad_flags; unsigned int ad_inited; int ad_options; @@ -256,9 +274,10 @@ struct adouble { */ char *ad_m_name; /* mac name for open fork */ int ad_m_namelen; + struct adouble_fops *ad_ops; - char *(*ad_path)(const char *, int); - int (*ad_mkrf)(char *); + + u_int16_t ad_open_forks; /* open forks (by others) */ #ifdef USE_MMAPPED_HEADERS char *ad_data; @@ -267,13 +286,28 @@ struct adouble { #endif }; +struct adouble_fops { + char *(*ad_path)(const char *, int); + int (*ad_mkrf)(char *); + + int (*ad_rebuild_header)(struct adouble *); + int (*ad_check_header)(struct adouble *, struct stat *); + int (*ad_header_read)(struct adouble *, struct stat *); + + int (*ad_header_upgrade)(struct adouble *, char *); + +}; + #define ADFLAGS_DF (1<<0) -#define ADFLAGS_HF (1<<1) +#define ADFLAGS_HF (1<<1) #define ADFLAGS_DIR (1<<2) #define ADFLAGS_NOADOUBLE (1<<3) #define ADFLAGS_V1COMPAT (1<<4) #define ADFLAGS_NOHF (1<<5) /* not an error if no ressource fork */ #define ADFLAGS_RDONLY (1<<6) /* don't try readwrite */ +#define ADFLAGS_OPENFORKS (1<<7) /* check for open fork in ad_metadata function */ +#define ADFLAGS_RF (1<<8) +#define ADFLAGS_MD ADFLAGS_HF /* (1<<9) */ /* adouble v2 cnid cache */ #define ADVOL_NODEV (1 << 0) @@ -363,8 +397,10 @@ struct adouble { #define AD_AFPFILEI_GROUP (1 << 1) /* ignore group */ #define AD_AFPFILEI_BLANKACCESS (1 << 2) /* blank access permissions */ -#define ad_dfileno(ad) ((ad)->ad_df.adf_fd) -#define ad_hfileno(ad) ((ad)->ad_hf.adf_fd) +#define ad_data_fileno(ad) ((ad)->ad_data_fork.adf_fd) +#define ad_reso_fileno(ad) ((ad)->ad_resource_fork.adf_fd) +#define ad_meta_fileno(ad) ((ad)->ad_md->adf_fd) + #define ad_getversion(ad) ((ad)->ad_version) #define ad_getentrylen(ad,eid) ((ad)->ad_eid[(eid)].ade_len) @@ -373,14 +409,17 @@ struct adouble { #define ad_getentryoff(ad,eid) ((ad)->ad_eid[(eid)].ade_off) #define ad_entry(ad,eid) ((caddr_t)(ad)->ad_data + \ (ad)->ad_eid[(eid)].ade_off) -#define ad_getoflags(ad,adf) (((adf)&ADFLAGS_HF) ? \ - (ad)->ad_hf.adf_flags : (ad)->ad_df.adf_flags) -#define ad_get_HF_flags(ad) ((ad)->ad_hf.adf_flags) +#define ad_get_HF_flags(ad) ((ad)->ad_resource_fork.adf_flags) +#define ad_get_MD_flags(ad) ((ad)->ad_md->adf_flags) + +/* ad_flush.c + +*/ +extern int ad_rebuild_adouble_header __P((struct adouble *)); +extern int ad_rebuild_sfm_header __P((struct adouble *)); -/* ad_flush.c */ -extern void ad_rebuild_header __P((struct adouble *)); -extern int ad_flush __P((struct adouble *, int)); +extern int ad_flush __P((struct adouble *)); extern int ad_close __P((struct adouble *, int)); /* ad_lock.c */ @@ -408,6 +447,7 @@ extern char *ad_dir __P((const char *)); extern char *ad_path __P((const char *, int)); extern char *ad_path_osx __P((const char *, int)); extern char *ad_path_ads __P((const char *, int)); +extern char *ad_path_sfm __P((const char *, int)); extern int ad_mode __P((const char *, int)); extern int ad_mkdir __P((const char *, int)); @@ -419,10 +459,9 @@ extern int ad_stat __P((const char *, struct stat *)); extern int ad_metadata __P((const char *, int, struct adouble *)); #define ad_open_metadata(name, flags, mode, adp)\ - ad_open(name, ADFLAGS_HF|(flags), O_RDWR |(mode), 0666, (adp)) + ad_open(name, ADFLAGS_MD|(flags), O_RDWR |(mode), 0666, (adp)) -#define ad_flush_metadata(adp) ad_flush( (adp), ADFLAGS_HF) -#define ad_close_metadata(adp) ad_close( (adp), ADFLAGS_HF) +#define ad_close_metadata(adp) ad_close( (adp), ADFLAGS_MD) /* build a resource fork mode from the data fork mode: * remove X mode and extend header to RW if R or W (W if R for locking), diff --git a/libatalk/adouble/ad_attr.c b/libatalk/adouble/ad_attr.c index 7168f8fe..e95e36e6 100644 --- a/libatalk/adouble/ad_attr.c +++ b/libatalk/adouble/ad_attr.c @@ -1,5 +1,5 @@ /* - * $Id: ad_attr.c,v 1.5 2005-04-28 20:49:51 bfernhomberg Exp $ + * $Id: ad_attr.c,v 1.6 2006-09-29 09:39:16 didg Exp $ */ #ifdef HAVE_CONFIG_H @@ -33,12 +33,17 @@ int ad_getattr(const struct adouble *ad, u_int16_t *attr) else return -1; + *attr |= htons(ad->ad_open_forks); + return 0; } /* ----------------- */ -int ad_setattr(const struct adouble *ad, const u_int16_t attr) +int ad_setattr(const struct adouble *ad, const u_int16_t attribute) { + /* we don't save open forks indicator */ + u_int16_t attr = attribute & ~htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN); + if (ad->ad_version == AD_VERSION1) { if (ad_getentryoff(ad, ADEID_FILEI)) { memcpy(ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR, &attr, @@ -107,7 +112,7 @@ char temp[ADEDLEN_PRIVSYN]; * note inode and device are opaques and not in network order * only use the ID if adouble is writable for us. */ - if (adp && ( adp->ad_options & ADVOL_CACHE) && ( adp->ad_hf.adf_flags & O_RDWR ) + if (adp && ( adp->ad_options & ADVOL_CACHE) && ( adp->ad_md->adf_flags & O_RDWR ) && sizeof(dev_t) == ad_getentrylen(adp, ADEID_PRIVDEV) && sizeof(ino_t) == ad_getentrylen(adp,ADEID_PRIVINO) && sizeof(temp) == ad_getentrylen(adp,ADEID_PRIVSYN) diff --git a/libatalk/adouble/ad_date.c b/libatalk/adouble/ad_date.c index 6324679b..c3ab1b77 100644 --- a/libatalk/adouble/ad_date.c +++ b/libatalk/adouble/ad_date.c @@ -1,5 +1,5 @@ /* - * $Id: ad_date.c,v 1.4 2005-04-28 20:49:51 bfernhomberg Exp $ + * $Id: ad_date.c,v 1.5 2006-09-29 09:39:16 didg Exp $ */ #ifdef HAVE_CONFIG_H @@ -19,6 +19,10 @@ int ad_setdate(const struct adouble *ad, date = AD_DATE_FROM_UNIX(date); if (ad->ad_version == AD_VERSION1) { + + if (!ad_getentryoff(ad, ADEID_FILEI)) + return -1; + if (dateoff > AD_DATE_BACKUP) return -1; memcpy(ad_entry(ad, ADEID_FILEI) + dateoff, &date, sizeof(date)); @@ -46,6 +50,8 @@ int ad_getdate(const struct adouble *ad, if (ad->ad_version == AD_VERSION1) { if (dateoff > AD_DATE_BACKUP) return -1; + if (!ad_getentryoff(ad, ADEID_FILEI)) + return -1; memcpy(date, ad_entry(ad, ADEID_FILEI) + dateoff, sizeof(u_int32_t)); } else if (ad->ad_version == AD_VERSION2) { diff --git a/libatalk/adouble/ad_flush.c b/libatalk/adouble/ad_flush.c index c92daddf..7cef3f7e 100644 --- a/libatalk/adouble/ad_flush.c +++ b/libatalk/adouble/ad_flush.c @@ -1,5 +1,5 @@ /* - * $Id: ad_flush.c,v 1.7 2005-04-28 20:49:52 bfernhomberg Exp $ + * $Id: ad_flush.c,v 1.8 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -27,11 +27,11 @@ #include #endif /* HAVE_CONFIG_H */ +#include #include #include #include -#include #include #include "ad_private.h" @@ -50,8 +50,10 @@ AD_DEV, AD_INO, AD_SYN, AD_ID #define EID_DISK(a) (set_eid[a]) #endif -/* rebuild the header */ -void ad_rebuild_header(struct adouble *ad) +/* rebuild the adouble header + * XXX should be in a separate file ? +*/ +int ad_rebuild_adouble_header(struct adouble *ad) { u_int32_t eid; u_int32_t temp; @@ -96,16 +98,83 @@ void ad_rebuild_header(struct adouble *ad) } nent = htons( nent ); memcpy(nentp, &nent, sizeof( nent )); + return ad_getentryoff(ad, ADEID_RFORK); +} + +/* ------------------- + * XXX copy only header with same size or comment + * doesn't work well for adouble with different version. + * +*/ +int ad_copy_header(struct adouble *add, struct adouble *ads) +{ + u_int32_t eid; + int len; + + for ( eid = 0; eid < ADEID_MAX; eid++ ) { + if ( ads->ad_eid[ eid ].ade_off == 0 ) { + continue; + } + + if ( add->ad_eid[ eid ].ade_off == 0 ) { + continue; + } + + len = ads->ad_eid[ eid ].ade_len; + if (!len) { + continue; + } + + if (eid != ADEID_COMMENT && add->ad_eid[ eid ].ade_len != len ) { + continue; + } + + ad_setentrylen( add, eid, len ); + memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len ); + } + add->ad_rlen = ads->ad_rlen; + return 0; } +/* ------------------- */ +int ad_rebuild_sfm_header(struct adouble *ad) +{ + u_int32_t eid; + u_int32_t temp; + + u_int16_t attr; + char *buf, *nentp; -int ad_flush( ad, adflags ) + /* + * Rebuild any header information that might have changed. + */ + buf = ad->ad_data; + /* FIXME */ +// temp = htonl( ad->ad_magic ); + temp = ad->ad_magic; + memcpy(buf, &temp, sizeof( temp )); + +// temp = htonl( ad->ad_version ); + temp = ad->ad_version; + memcpy(buf +4, &temp, sizeof( temp )); + + /* need to save attrib */ + if (!ad_getattr(ad, &attr)) { + attr &= ~htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN); + + memcpy(buf +48 +4, &attr, sizeof(attr)); + + } + return AD_SFM_LEN; +} + + +int ad_flush( ad ) struct adouble *ad; - int adflags; { int len; - if (( adflags & ADFLAGS_HF ) && ( ad->ad_hf.adf_flags & O_RDWR )) { + if (( ad->ad_md->adf_flags & O_RDWR )) { /* sync our header */ if (ad->ad_rlen > 0xffffffff) { ad_setentrylen(ad, ADEID_RFORK, 0xffffffff); @@ -113,10 +182,9 @@ int ad_flush( ad, adflags ) else { ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen); } - ad_rebuild_header(ad); - len = ad_getentryoff(ad, ADEID_RFORK); - /* now flush it out */ - if (adf_pwrite(&ad->ad_hf, ad->ad_data, len, 0) != len) { + len = ad->ad_ops->ad_rebuild_header(ad); + + if (adf_pwrite(ad->ad_md, ad->ad_data, len, 0) != len) { if ( errno == 0 ) { errno = EIO; } @@ -134,23 +202,44 @@ int ad_close( ad, adflags ) { int err = 0; - if (( adflags & ADFLAGS_DF ) && ad->ad_df.adf_fd != -1 && - !(--ad->ad_df.adf_refcount)) { - if ( close( ad->ad_df.adf_fd ) < 0 ) { + if (( adflags & ADFLAGS_DF ) && ad_data_fileno(ad) != -1 && + !(--ad->ad_data_fork.adf_refcount)) { + if ( close( ad_data_fileno(ad) ) < 0 ) { err = -1; } - ad->ad_df.adf_fd = -1; - adf_lock_free(&ad->ad_df); + ad_data_fileno(ad) = -1; + adf_lock_free(&ad->ad_data_fork); } - if (( adflags & ADFLAGS_HF ) && ad->ad_hf.adf_fd != -1 && - !(--ad->ad_hf.adf_refcount)) { - if ( close( ad->ad_hf.adf_fd ) < 0 ) { + if (!( adflags & ADFLAGS_HF )) { + return err; + } + + /* meta /resource fork */ + + if ( ad_meta_fileno(ad) != -1 && !(--ad->ad_md->adf_refcount)) { + if ( close( ad_meta_fileno(ad) ) < 0 ) { err = -1; } - ad->ad_hf.adf_fd = -1; - adf_lock_free(&ad->ad_hf); + ad_meta_fileno(ad) = -1; + adf_lock_free(ad->ad_md); } - return( err ); + if (ad->ad_flags != AD_VERSION1_SFM) { + return err; + } + + if ((adflags & ADFLAGS_DIR)) { + return err; + } + + if ( ad_reso_fileno(ad) != -1 && !(--ad->ad_resource_fork.adf_refcount)) { + if ( close( ad_reso_fileno(ad) ) < 0 ) { + err = -1; + } + ad_reso_fileno(ad) = -1; + adf_lock_free(&ad->ad_resource_fork); + } + + return err; } diff --git a/libatalk/adouble/ad_lock.c b/libatalk/adouble/ad_lock.c index 77cd5025..31e8c71a 100644 --- a/libatalk/adouble/ad_lock.c +++ b/libatalk/adouble/ad_lock.c @@ -1,5 +1,5 @@ /* - * $Id: ad_lock.c,v 1.12 2005-04-28 20:49:52 bfernhomberg Exp $ + * $Id: ad_lock.c,v 1.13 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1998,1999 Adrian Sun (asun@zoology.washington.edu) * All Rights Reserved. See COPYRIGHT for more information. @@ -261,27 +261,31 @@ int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int locktype, lock.l_start = off; type = locktype; if (eid == ADEID_DFORK) { - adf = &ad->ad_df; + adf = &ad->ad_data_fork; if ((type & ADLOCK_FILELOCK)) { - if (ad_hfileno(ad) != -1) { + if (ad_meta_fileno(ad) != -1) { /* META */ + adf = ad->ad_md; lock.l_start = df2off(off); - adf = &ad->ad_hf; } } } else { /* rfork */ - adf = &ad->ad_hf; - if (adf->adf_fd == -1) { - /* there's no resource fork. return a lock error + if (ad_meta_fileno(ad) == -1 || ad_reso_fileno(ad) == -1) { + /* there's no meta data. return a lock error * otherwise if a second process is able to create it * locks are a mess. */ errno = EACCES; return -1; } - if (type & ADLOCK_FILELOCK) + if (type & ADLOCK_FILELOCK) { + adf = ad->ad_md; /* either resource or meta data (set in ad_open) */ lock.l_start = hf2off(off); - else + } + else { + /* we really want the resource fork it's a byte lock */ + adf = &ad->ad_resource_fork; lock.l_start += ad_getentryoff(ad, eid); + } } /* NOTE: we can't write lock a read-only file. on those, we just * make sure that we have a read lock set. that way, we at least prevent @@ -399,18 +403,18 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off) lock.l_start = off; if (eid == ADEID_DFORK) { - adf = &ad->ad_df; - if ((ad_hfileno(ad) != -1)) { - adf = &ad->ad_hf; + adf = &ad->ad_data_fork; + if ((ad_meta_fileno(ad) != -1)) { + adf = ad->ad_md; lock.l_start = df2off(off); } } else { /* rfork */ - if ((ad_hfileno(ad) == -1)) { + if ((ad_meta_fileno(ad) == -1)) { /* there's no resource fork. return no lock */ return 0; } - adf = &ad->ad_hf; + adf = ad->ad_md; lock.l_start = hf2off(off); } @@ -448,9 +452,10 @@ int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype lock.l_start = off; type = locktype; if (eid == ADEID_DFORK) { - adf = &ad->ad_df; + adf = &ad->ad_data_fork; } else { - adf = &ad->ad_hf; + /* FIXME META */ + adf = &ad->ad_resource_fork; if (adf->adf_fd == -1) { /* there's no resource fork. return success */ return 0; @@ -515,9 +520,9 @@ int ad_excl_lock(struct adouble *ad, const u_int32_t eid) lock.l_len = 0; if (eid == ADEID_DFORK) { - adf = &ad->ad_df; + adf = &ad->ad_data_fork; } else { - adf = &ad->ad_hf; + adf = &ad->ad_resource_fork; lock.l_start = ad_getentryoff(ad, eid); } @@ -530,10 +535,18 @@ int ad_excl_lock(struct adouble *ad, const u_int32_t eid) /* --------------------- */ void ad_fcntl_unlock(struct adouble *ad, const int user) { - if (ad->ad_df.adf_fd != -1) { - adf_unlock(&ad->ad_df, user); + if (ad_data_fileno(ad) != -1) { + adf_unlock(&ad->ad_data_fork, user); } - if (ad->ad_hf.adf_fd != -1) { - adf_unlock(&ad->ad_hf, user); + if (ad_reso_fileno(ad) != -1) { + adf_unlock(&ad->ad_resource_fork, user); } + + if (ad->ad_flags != AD_VERSION1_SFM) { + return; + } + if (ad_meta_fileno(ad) != -1) { + adf_unlock(&ad->ad_metadata_fork, user); + } + } diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 4d5a2850..09f2ed3d 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1,5 +1,5 @@ /* - * $Id: ad_open.c,v 1.36 2006-09-19 23:00:50 didg Exp $ + * $Id: ad_open.c,v 1.37 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) * Copyright (c) 1990,1991 Regents of The University of Michigan. @@ -193,6 +193,15 @@ static const struct entry entry_order_osx[ADEID_NUM_OSX +1] = { {0, 0, 0} }; +#define ADEID_NUM_SFM 3 +static const struct entry entry_order_sfm[ADEID_NUM_SFM +1] = { + {ADEID_FINDERI, 16, ADEDLEN_FINDERI}, /* 9 */ + {ADEID_SFMRESERVE2, 16+32, 6}, /* 21 */ + {ADEID_FILEI, 60, ADEDLEN_FILEI}, /* 7 */ + + {0, 0, 0} +}; + #endif /* AD_VERSION == AD_VERSION2 */ #if AD_VERSION == AD_VERSION2 @@ -213,7 +222,7 @@ static int ad_update(struct adouble *ad, const char *path) if (!path || ad->ad_flags != AD_VERSION2) return 0; - if (!(ad->ad_hf.adf_flags & O_RDWR)) { + if (!(ad->ad_md->adf_flags & O_RDWR)) { /* we were unable to open the file read write the last time */ return 0; } @@ -235,7 +244,7 @@ static int ad_update(struct adouble *ad, const char *path) if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0) goto bail_err; - fd = ad->ad_hf.adf_fd; + fd = ad->ad_md->adf_fd; if (fstat(fd, &st)) { goto bail_lock; @@ -308,7 +317,7 @@ static int ad_update(struct adouble *ad, const char *path) /* rebuild the header and cleanup */ LOG(log_debug, logtype_default, "updated AD2 header %s", path); - ad_flush(ad, ADFLAGS_HF ); + ad_flush(ad ); ret = 0; bail_lock: @@ -336,7 +345,7 @@ static int ad_convert(struct adouble *ad, const char *path) return 0; } - if (!(ad->ad_hf.adf_flags & ( O_RDWR))) { + if (!(ad->ad_md->adf_flags & ( O_RDWR))) { /* we were unable to open the file read write the last time */ return 0; } @@ -361,7 +370,7 @@ static int ad_convert(struct adouble *ad, const char *path) goto bail_err; /* we reuse fd from the resource fork */ - fd = ad->ad_hf.adf_fd; + fd = ad->ad_md->adf_fd; if (ad->ad_eid[ADEID_RFORK].ade_off) { shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off; @@ -466,7 +475,7 @@ static int ad_convert(struct adouble *ad, const char *path) memset(ad_entry(ad, ADEID_PRODOSFILEI), 0, ADEDLEN_PRODOSFILEI); /* rebuild the header and cleanup */ - ad_flush(ad, ADFLAGS_HF ); + ad_flush(ad ); ret = 0; bail_lock: @@ -556,7 +565,7 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) struct stat st; /* read the header */ - if ((header_len = adf_pread( &ad->ad_hf, buf, sizeof(ad->ad_data), 0)) < 0) { + if ((header_len = adf_pread( ad->ad_md, buf, sizeof(ad->ad_data), 0)) < 0) { return -1; } if (header_len < AD_HEADER_LEN) { @@ -639,7 +648,7 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) if (hst == NULL) { hst = &st; - if (fstat(ad->ad_hf.adf_fd, &st) < 0) { + if (fstat(ad->ad_md->adf_fd, &st) < 0) { return 1; /* fail silently */ } } @@ -664,6 +673,115 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) return 0; } +/* --------------------------- + SFM structure + */ +#if 0 +typedef struct { + byte afpi_Signature[4]; /* Must be 0x00504641 */ + byte afpi_Version[4]; /* Must be 0x00010000 */ + byte afpi_Reserved1[4]; + byte afpi_BackupTime[4]; /* Backup time for the file/dir */ + byte finderinfo[32]; /* Finder info */ + byte afpi_ProDosInfo[6]; /* ProDos Info */ + byte afpi_Reserved2[6]; +} sfm_info; +#endif + +static int ad_header_sfm_read(struct adouble *ad, struct stat *hst) +{ + char *buf = ad->ad_data; + const struct entry *eid; + u_int16_t nentries; + int len; + ssize_t header_len; + static int warning = 0; + struct stat st; + + /* read the header */ + if ((header_len = adf_pread( ad->ad_md, buf, sizeof(ad->ad_data), 0)) < 0) { + return -1; + } + if (header_len != AD_SFM_LEN) { + errno = EIO; + return -1; + } + + memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic )); + memcpy(&ad->ad_version, buf + 4, sizeof( ad->ad_version )); + + /* FIXME in the the great Microsoft tradition they aren't in network order */ +#if 0 + if (ad->ad_magic == SFM_MAGIC && ad->ad_version == AD_VERSION1) { + if (!warning) { + LOG(log_debug, logtype_default, "notice: fixing up byte-swapped v1 magic/version."); + warning++; + } + + } else { + ad->ad_magic = ntohl( ad->ad_magic ); + ad->ad_version = ntohl( ad->ad_version ); + } +#endif + if ((ad->ad_magic != SFM_MAGIC) || ((ad->ad_version != AD_VERSION1) )) { + errno = EIO; + LOG(log_debug, logtype_default, "ad_header_sfm_read: can't parse AppleDouble header."); + return -1; + } + + /* reinit adouble table */ + eid = entry_order_sfm; + while (eid->id) { + ad->ad_eid[eid->id].ade_off = eid->offset; + ad->ad_eid[eid->id].ade_len = eid->len; + eid++; + } + + /* steal some prodos for attribute */ + { + + u_int16_t attribute; + memcpy(&attribute, buf + 48 +4, sizeof(attribute)); + ad_setattr(ad, attribute ); + } + + if (ad->ad_resource_fork.adf_fd != -1) { + /* we have a resource fork use it rather than the metadata */ + if (fstat(ad->ad_resource_fork.adf_fd, &st) < 0) { + /* XXX set to zero ? + ad->ad_rlen = 0; + */ + return 1; + } + ad->ad_rlen = st.st_size; + hst = &st; + } + else if (hst == NULL) { + hst = &st; + if (fstat(ad->ad_md->adf_fd, &st) < 0) { + return 1; /* fail silently */ + } + } + + /* fix up broken dates */ + if (ad->ad_version == AD_VERSION1) { + u_int32_t aint; + + /* check to see if the ad date is wrong. just see if we have + * a modification date in the future. */ + if (((ad_getdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, &aint)) == 0) && + (aint > TIMEWARP_DELTA + hst->st_mtime)) { + ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, aint - AD_DATE_DELTA); + ad_getdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, &aint); + ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, aint - AD_DATE_DELTA); + ad_getdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, &aint); + ad_setdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, aint - AD_DATE_DELTA); + } + } + + return 0; +} + /* --------------------------------------- * Put the .AppleDouble where it needs to be: * @@ -802,14 +920,49 @@ ad_path_ads( path, adflags ) strlcat( pathbuf, slash, MAXPATHLEN +1); strlcat( pathbuf, "/Afp_AfpInfo", MAXPATHLEN +1); + return( pathbuf ); +} -#if 0 - if ((adflags & ADFLAGS_HF)) { - strlcat( pathbuf, "Afp_AfpInfo", MAXPATHLEN +1); +/* ---------------------- + * mostly the same as ads, only case change Afp --> AFP and AFP_Resoure +*/ +char * +ad_path_sfm( path, adflags ) + const char *path; + int adflags; +{ + static char pathbuf[ MAXPATHLEN + 1]; + char c, *slash, buf[MAXPATHLEN + 1]; + size_t l; + + l = strlcpy(buf, path, MAXPATHLEN +1); + if ( adflags & ADFLAGS_DIR ) { + strcpy( pathbuf, buf); + if ( *buf != '\0' && l < MAXPATHLEN) { + pathbuf[l++] = '/'; + pathbuf[l] = 0; + } + slash = ".Parent"; + } else { + if (NULL != ( slash = strrchr( buf, '/' )) ) { + c = *++slash; + *slash = '\0'; + strcpy( pathbuf, buf); + *slash = c; + } else { + pathbuf[ 0 ] = '\0'; + slash = buf; + } + } + strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1); + strlcat( pathbuf, slash, MAXPATHLEN +1); + + if ((adflags == ADFLAGS_RF)) { + strlcat( pathbuf, "/AFP_Resource", MAXPATHLEN +1); + } else { - strlcat( pathbuf, "Afp_Resource", MAXPATHLEN +1); + strlcat( pathbuf, "/AFP_AfpInfo", MAXPATHLEN +1); } -#endif return( pathbuf ); } @@ -1025,21 +1178,97 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags); #define AD_SET(a) a = 0 #endif +/* --------------------------- */ +static int ad_check_size(struct adouble *ad, struct stat *st) +{ + if (st->st_size > 0 && st->st_size < AD_DATASZ1) + return 1; + return 0; +} + +/* --------------------------- */ +static int ad_check_size_sfm(struct adouble *ad, struct stat *st) +{ + if (st->st_size > 0 && st->st_size < AD_SFM_LEN) + return 1; + return 0; +} + +/* --------------------------- */ +static int ad_header_upgrade(struct adouble *ad, char *name) +{ +#if AD_VERSION == AD_VERSION2 + int ret; + if ( (ret = ad_convert(ad, name)) < 0 || (ret = ad_update(ad, name) < 0)) { + return ret; + } +#endif + return 0; +} + +/* --------------------------- */ +static int ad_header_upgrade_none(struct adouble *ad, char *name) +{ + return 0; +} + +/* --------------------------- */ +static struct adouble_fops ad_osx = { + &ad_path_osx, + &ad_mkrf_osx, + &ad_rebuild_adouble_header, + &ad_check_size, + + &ad_header_read, + &ad_header_upgrade, +}; + +static struct adouble_fops ad_ads = { + &ad_path_ads, + &ad_mkrf_ads, + &ad_rebuild_adouble_header, + &ad_check_size, + + &ad_header_read, + &ad_header_upgrade, +}; + +static struct adouble_fops ad_sfm = { + &ad_path_sfm, + &ad_mkrf_ads, + &ad_rebuild_sfm_header, + &ad_check_size_sfm, + + &ad_header_sfm_read, + &ad_header_upgrade_none, +}; + +static struct adouble_fops ad_adouble = { + &ad_path, + &ad_mkrf, + &ad_rebuild_adouble_header, + &ad_check_size, + + &ad_header_read, + &ad_header_upgrade, +}; + + void ad_init(struct adouble *ad, int flags, int options) { memset( ad, 0, sizeof( struct adouble ) ); ad->ad_flags = flags; if (flags == AD_VERSION2_OSX) { - ad->ad_path = ad_path_osx; - ad->ad_mkrf = ad_mkrf_osx; + ad->ad_ops = &ad_osx; } else if (flags == AD_VERSION1_ADS) { - ad->ad_path = ad_path_ads; - ad->ad_mkrf = ad_mkrf_ads; + ad->ad_ops = &ad_ads; + } + else if (flags == AD_VERSION1_SFM) { + ad->ad_ops = &ad_sfm; } else { - ad->ad_path = ad_path; - ad->ad_mkrf = ad_mkrf; + ad->ad_ops = &ad_adouble; } ad->ad_options = options; } @@ -1053,52 +1282,69 @@ int ad_open( path, adflags, oflags, mode, ad ) int adflags, oflags, mode; struct adouble *ad; { - struct stat st; + struct stat st_dir; + struct stat st_meta; + struct stat *pst = NULL; char *ad_p; int hoflags, admode; int st_invalid = -1; int open_df = 0; if (ad->ad_inited != AD_INITED) { - ad_dfileno(ad) = -1; - ad_hfileno(ad) = -1; - adf_lock_init(&ad->ad_df); - adf_lock_init(&ad->ad_hf); + ad_data_fileno(ad) = -1; + ad_reso_fileno(ad) = -1; + adf_lock_init(&ad->ad_data_fork); + adf_lock_init(&ad->ad_resource_fork); + if (ad->ad_flags != AD_VERSION1_SFM) { + ad->ad_md = &ad->ad_resource_fork; + } + else { + adf_lock_init(&ad->ad_metadata_fork); + ad->ad_md = &ad->ad_metadata_fork; + ad_meta_fileno(ad) = -1; + } ad->ad_inited = AD_INITED; ad->ad_refcount = 1; + ad->ad_open_forks = 0; + } + else { + ad->ad_open_forks = ((ad->ad_data_fork.adf_refcount > 0) ? ATTRBIT_DOPEN : 0); + /* XXX not true if we have a meta data fork ? */ + if ((ad->ad_resource_fork.adf_refcount > ad->ad_data_fork.adf_refcount)) + ad->ad_open_forks |= ATTRBIT_ROPEN; } if ((adflags & ADFLAGS_DF)) { - if (ad_dfileno(ad) == -1) { + if (ad_data_fileno(ad) == -1) { hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; admode = mode; if ((oflags & O_CREAT)) { - st_invalid = ad_mode_st(path, &admode, &st); + st_invalid = ad_mode_st(path, &admode, &st_dir); if ((ad->ad_options & ADVOL_UNIXPRIV)) { admode = mode; } } - ad->ad_df.adf_fd =open( path, hoflags, admode ); - if (ad->ad_df.adf_fd < 0 ) { + ad->ad_data_fork.adf_fd =open( path, hoflags, admode ); + if (ad->ad_data_fork.adf_fd < 0 ) { if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) { hoflags = oflags; - ad->ad_df.adf_fd = open( path, hoflags, admode ); + ad->ad_data_fork.adf_fd = open( path, hoflags, admode ); } } - if ( ad->ad_df.adf_fd < 0) + if ( ad->ad_data_fork.adf_fd < 0) return -1; - AD_SET(ad->ad_df.adf_off); - ad->ad_df.adf_flags = hoflags; + AD_SET(ad->ad_data_fork.adf_off); + ad->ad_data_fork.adf_flags = hoflags; if (!st_invalid) { /* just created, set owner if admin (root) */ - ad_chown(path, &st); + ad_chown(path, &st_dir); } } else { /* the file is already open... but */ if ((oflags & ( O_RDWR | O_WRONLY)) && /* we want write access */ - !(ad->ad_df.adf_flags & ( O_RDWR | O_WRONLY))) /* and it was denied the first time */ + !(ad->ad_data_fork.adf_flags & ( O_RDWR | O_WRONLY))) /* and it was denied the first time */ { errno = EACCES; return -1; @@ -1112,15 +1358,17 @@ int ad_open( path, adflags, oflags, mode, ad ) */ } open_df = ADFLAGS_DF; - ad->ad_df.adf_refcount++; + ad->ad_data_fork.adf_refcount++; } if (!(adflags & ADFLAGS_HF)) return 0; + + /* ****************************************** */ - if (ad_hfileno(ad) != -1) { /* the file is already open */ + if (ad_meta_fileno(ad) != -1) { /* the file is already open */ if ((oflags & ( O_RDWR | O_WRONLY)) && - !(ad->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) { + !(ad->ad_md->adf_flags & ( O_RDWR | O_WRONLY))) { if (open_df) { /* don't call with ADFLAGS_HF because we didn't open ressource fork */ ad_close( ad, open_df ); @@ -1129,25 +1377,25 @@ int ad_open( path, adflags, oflags, mode, ad ) return -1; } ad_refresh(ad); - ad->ad_hf.adf_refcount++; - return 0; + ad->ad_md->adf_refcount++; + goto sfm; } - ad_p = ad->ad_path( path, adflags ); + ad_p = ad->ad_ops->ad_path( path, adflags ); hoflags = oflags & ~O_CREAT; if (!(adflags & ADFLAGS_RDONLY)) { hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; } - ad->ad_hf.adf_fd = open( ad_p, hoflags, 0 ); - if (ad->ad_hf.adf_fd < 0 ) { + ad->ad_md->adf_fd = open( ad_p, hoflags, 0 ); + if (ad->ad_md->adf_fd < 0 ) { if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) { hoflags = oflags & ~O_CREAT; - ad->ad_hf.adf_fd = open( ad_p, hoflags, 0 ); + ad->ad_md->adf_fd = open( ad_p, hoflags, 0 ); } } - if ( ad->ad_hf.adf_fd < 0 ) { + if ( ad->ad_md->adf_fd < 0 ) { if (errno == ENOENT && (oflags & O_CREAT) ) { /* * We're expecting to create a new adouble header file, @@ -1156,47 +1404,47 @@ int ad_open( path, adflags, oflags, mode, ad ) */ admode = mode; errno = 0; - st_invalid = ad_mode_st(ad_p, &admode, &st); + st_invalid = ad_mode_st(ad_p, &admode, &st_dir); if ((ad->ad_options & ADVOL_UNIXPRIV)) { admode = mode; } admode = ad_hf_mode(admode); if ( errno == ENOENT && !(adflags & ADFLAGS_NOADOUBLE) && ad->ad_flags != AD_VERSION2_OSX) { - if (ad->ad_mkrf( ad_p) < 0) { + if (ad->ad_ops->ad_mkrf( ad_p) < 0) { return ad_error(ad, adflags); } admode = mode; - st_invalid = ad_mode_st(ad_p, &admode, &st); + st_invalid = ad_mode_st(ad_p, &admode, &st_dir); if ((ad->ad_options & ADVOL_UNIXPRIV)) { admode = mode; } admode = ad_hf_mode(admode); } /* retry with O_CREAT */ - ad->ad_hf.adf_fd = open( ad_p, oflags,admode ); - if ( ad->ad_hf.adf_fd < 0 ) { + ad->ad_md->adf_fd = open( ad_p, oflags,admode ); + if ( ad->ad_md->adf_fd < 0 ) { return ad_error(ad, adflags); } - ad->ad_hf.adf_flags = oflags; + ad->ad_md->adf_flags = oflags; /* just created, set owner if admin owner (root) */ if (!st_invalid) { - ad_chown(ad_p, &st); + ad_chown(ad_p, &st_dir); } } else { return ad_error(ad, adflags); } - } else if (fstat(ad->ad_hf.adf_fd, &st) == 0 && st.st_size == 0) { + } else if (fstat(ad->ad_md->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) { /* for 0 length files, treat them as new. */ - ad->ad_hf.adf_flags = hoflags| O_TRUNC; + ad->ad_md->adf_flags = hoflags| O_TRUNC; } else { - ad->ad_hf.adf_flags = hoflags; + ad->ad_md->adf_flags = hoflags; } - AD_SET(ad->ad_hf.adf_off); + AD_SET(ad->ad_md->adf_off); memset(ad->ad_eid, 0, sizeof( ad->ad_eid )); - ad->ad_hf.adf_refcount++; - if ((ad->ad_hf.adf_flags & ( O_TRUNC | O_CREAT ))) { + ad->ad_md->adf_refcount++; + if ((ad->ad_md->adf_flags & ( O_TRUNC | O_CREAT ))) { /* * This is a new adouble header file. Initialize the structure, * instead of reading it. @@ -1209,12 +1457,10 @@ int ad_open( path, adflags, oflags, mode, ad ) return -1; } } else { - /* Read the adouble header in and parse it.*/ - if ((ad_header_read( ad , &st) < 0) -#if AD_VERSION == AD_VERSION2 - || (ad_convert(ad, ad_p) < 0) || (ad_update(ad, ad_p) < 0) -#endif /* AD_VERSION == AD_VERSION2 */ - ) { + /* Read the adouble header in and parse it.*/ + if (ad->ad_ops->ad_header_read( ad , pst) < 0 + || ad->ad_ops->ad_header_upgrade(ad, ad_p) < 0) + { int err = errno; ad_close( ad, adflags ); @@ -1222,6 +1468,68 @@ int ad_open( path, adflags, oflags, mode, ad ) return -1; } } + + /* ****************************************** */ + /* open the resource fork if SFM */ +sfm: + if (ad->ad_flags != AD_VERSION1_SFM) { + return 0; + } + + if ((adflags & ADFLAGS_DIR)) { + /* no resource fork for directories / volumes XXX it's false! */ + return 0; + } + + /* untrue yet but ad_close will decremente it*/ + ad->ad_resource_fork.adf_refcount++; + + if (ad_reso_fileno(ad) != -1) { /* the file is already open */ + if ((oflags & ( O_RDWR | O_WRONLY)) && + !(ad->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) { + + ad_close( ad, open_df | ADFLAGS_HF); + errno = EACCES; + return -1; + } + return 0; + } + + ad_p = ad->ad_ops->ad_path( path, ADFLAGS_RF ); + + hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; + ad->ad_resource_fork.adf_fd = open( ad_p, hoflags, admode ); + admode = mode; + st_invalid = ad_mode_st(ad_p, &admode, &st_dir); + + if ((ad->ad_options & ADVOL_UNIXPRIV)) { + admode = mode; + } + + if (ad->ad_resource_fork.adf_fd < 0 ) { + if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) { + hoflags = oflags; + ad->ad_resource_fork.adf_fd =open( ad_p, hoflags, admode ); + } + } + + if ( ad->ad_resource_fork.adf_fd < 0) { + int err = errno; + + ad_close( ad, adflags ); + errno = err; + return -1; + } + + AD_SET(ad->ad_resource_fork.adf_off); + ad->ad_resource_fork.adf_flags = hoflags; + if ((oflags & O_CREAT) && !st_invalid) { + /* just created, set owner if admin (root) */ + ad_chown(ad_p, &st_dir); + } + else if (!fstat(ad->ad_resource_fork.adf_fd, &st_meta)) { + ad->ad_rlen = st_meta.st_size; + } return 0 ; } @@ -1232,8 +1540,9 @@ int ad_metadata(const char *name, int flags, struct adouble *adp) { uid_t uid; int ret, err; + int dir = flags & ADFLAGS_DIR; - if ((ret = ad_open(name, ADFLAGS_HF | flags, O_RDONLY, 0, adp)) < 0 && errno == EACCES) { + if ((ret = ad_open(name, ADFLAGS_HF | dir, O_RDONLY, 0, adp)) < 0 && errno == EACCES) { uid = geteuid(); if (seteuid(0)) { LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno)); @@ -1241,7 +1550,7 @@ int ad_metadata(const char *name, int flags, struct adouble *adp) return -1; } /* we are root open read only */ - ret = ad_open(name, ADFLAGS_HF|ADFLAGS_RDONLY|flags, O_RDONLY, 0, adp); + ret = ad_open(name, ADFLAGS_HF|ADFLAGS_RDONLY| dir, O_RDONLY, 0, adp); err = errno; if ( seteuid(uid) < 0) { LOG(log_error, logtype_default, "ad_metadata: can't seteuid back"); @@ -1249,6 +1558,28 @@ int ad_metadata(const char *name, int flags, struct adouble *adp) } errno = err; } + + if (!ret && (ADFLAGS_OPENFORKS & flags)) { + u_int16_t attrbits = adp->ad_open_forks; + + /* + we need to check if the file is open by another process. + it's slow so we only do it if we have to: + - it's requested. + - we don't already have the answer! + */ + + if (!(attrbits & ATTRBIT_ROPEN)) { + attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0; + attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0; + } + + if (!(attrbits & ATTRBIT_DOPEN)) { + attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0; + attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0; + } + adp->ad_open_forks = attrbits; + } return ret; } @@ -1273,6 +1604,10 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags) eid = entry_order2; else if (ad->ad_flags == AD_VERSION2_OSX) eid = entry_order_osx; + else if (ad->ad_flags == AD_VERSION1_SFM) { + ad->ad_magic = SFM_MAGIC; + eid = entry_order_sfm; + } else #endif eid = entry_order1; @@ -1320,8 +1655,8 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags) int ad_refresh(struct adouble *ad) { - if (ad->ad_hf.adf_fd < 0) + if (ad_meta_fileno(ad) < 0) return -1; - return ad_header_read(ad, NULL); + return ad->ad_ops->ad_header_read(ad, NULL); } diff --git a/libatalk/adouble/ad_read.c b/libatalk/adouble/ad_read.c index 5c3c9333..c5ad96e8 100644 --- a/libatalk/adouble/ad_read.c +++ b/libatalk/adouble/ad_read.c @@ -1,5 +1,5 @@ /* - * $Id: ad_read.c,v 1.6 2005-04-28 20:49:52 bfernhomberg Exp $ + * $Id: ad_read.c,v 1.7 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -71,17 +71,17 @@ ssize_t ad_read( ad, eid, off, buf, buflen) /* We're either reading the data fork (and thus the data file) * or we're reading anything else (and thus the header file). */ if ( eid == ADEID_DFORK ) { - cc = adf_pread(&ad->ad_df, buf, buflen, off); + cc = adf_pread(&ad->ad_data_fork, buf, buflen, off); } else { off_t r_off; - if ( ad_hfileno( ad ) == -1 ) { + if ( ad_reso_fileno( ad ) == -1 ) { /* resource fork is not open ( cf etc/afp/fork.c) */ return 0; } r_off = ad_getentryoff(ad, eid) + off; - if (( cc = adf_pread( &ad->ad_hf, buf, buflen, r_off )) < 0 ) { + if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 ) { return( -1 ); } /* @@ -91,7 +91,7 @@ ssize_t ad_read( ad, eid, off, buf, buflen) * FIXME : always false? */ if (r_off < ad_getentryoff(ad, ADEID_RFORK)) { - if ( ad->ad_hf.adf_flags & O_RDWR ) { + if ( ad->ad_resource_fork.adf_flags & O_RDWR ) { memcpy(buf, ad->ad_data + r_off, MIN(sizeof( ad->ad_data ) - r_off, cc)); } else { diff --git a/libatalk/adouble/ad_size.c b/libatalk/adouble/ad_size.c index bada1c36..b2b29cae 100644 --- a/libatalk/adouble/ad_size.c +++ b/libatalk/adouble/ad_size.c @@ -1,5 +1,5 @@ /* - * $Id: ad_size.c,v 1.6 2005-04-28 20:49:52 bfernhomberg Exp $ + * $Id: ad_size.c,v 1.7 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) * All rights reserved. See COPYRIGHT. @@ -19,7 +19,7 @@ off_t ad_size(const struct adouble *ad, const u_int32_t eid) if (eid == ADEID_DFORK) { struct stat st; - if (fstat(ad_dfileno(ad), &st) < 0) + if (fstat(ad_data_fileno(ad), &st) < 0) return 0; return st.st_size; } diff --git a/libatalk/adouble/ad_write.c b/libatalk/adouble/ad_write.c index d7bb789a..1331ae04 100644 --- a/libatalk/adouble/ad_write.c +++ b/libatalk/adouble/ad_write.c @@ -1,5 +1,5 @@ /* - * $Id: ad_write.c,v 1.8 2005-04-28 20:49:52 bfernhomberg Exp $ + * $Id: ad_write.c,v 1.9 2006-09-29 09:39:16 didg Exp $ * * Copyright (c) 1990,1995 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -60,23 +60,23 @@ ssize_t ad_write( ad, eid, off, end, buf, buflen ) if ( eid == ADEID_DFORK ) { if ( end ) { - if ( fstat( ad->ad_df.adf_fd, &st ) < 0 ) { + if ( fstat( ad_data_fileno(ad), &st ) < 0 ) { return( -1 ); } off = st.st_size - off; } - cc = adf_pwrite(&ad->ad_df, buf, buflen, off); + cc = adf_pwrite(&ad->ad_data_fork, buf, buflen, off); } else if ( eid == ADEID_RFORK ) { off_t r_off; if ( end ) { - if ( fstat( ad->ad_df.adf_fd, &st ) < 0 ) { + if ( fstat( ad_data_fileno(ad), &st ) < 0 ) { return( -1 ); } off = st.st_size - off -ad_getentryoff(ad, eid); } r_off = ad_getentryoff(ad, eid) + off; - cc = adf_pwrite(&ad->ad_hf, buf, buflen, r_off); + cc = adf_pwrite(&ad->ad_resource_fork, buf, buflen, r_off); /* sync up our internal buffer FIXME always false? */ if (r_off < ad_getentryoff(ad, ADEID_RFORK)) { @@ -155,7 +155,7 @@ int ad_rtruncate( ad, size ) struct adouble *ad; const off_t size; { - if ( sys_ftruncate( ad->ad_hf.adf_fd, + if ( sys_ftruncate( ad_reso_fileno(ad), size + ad->ad_eid[ ADEID_RFORK ].ade_off ) < 0 ) { return -1; } @@ -168,7 +168,7 @@ int ad_dtruncate(ad, size) struct adouble *ad; const off_t size; { - if (sys_ftruncate(ad->ad_df.adf_fd, size) < 0) { + if (sys_ftruncate(ad_data_fileno(ad), size) < 0) { return -1; } return 0; -- 2.39.2