/*
- * $Id: file.c,v 1.96 2005-04-28 20:49:41 bfernhomberg Exp $
+ * $Id: file.c,v 1.110 2009-09-21 12:35:05 franklahm Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
}
/* FIXME path : unix or mac name ? (for now it's unix name ) */
-void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
+void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
{
struct extmap *em;
void *ad_finder = NULL;
else {
memcpy(data, ufinderi, ADEDLEN_FINDERI);
chk_ext = 1;
- if (*upath == '.') { /* make it invisible */
+ if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
u_int16_t ashort;
ashort = htons(FINDERINFO_INVISIBLE);
- memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
+ memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
}
}
/** Only enter if no appledouble information and no finder information found. */
* 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
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;
case FILPBIT_ATTR :
if ( adp ) {
ad_getattr(adp, &ashort);
- } else if (*upath == '.') {
+ } else if (vol_inv_dots(vol) && *upath == '.') {
ashort = htons(ATTRBIT_INVISIBLE);
} else
ashort = 0;
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;
break;
case FILPBIT_FINFO :
- get_finderinfo(upath, adp, (char *)data);
+ get_finderinfo(vol, upath, adp, (char *)data);
data += ADEDLEN_FINDERI;
break;
struct adouble ad, *adp;
struct ofork *of;
char *upath;
- u_int16_t attrbits = 0;
int opened = 0;
int rc;
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?",
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( adp, ADFLAGS_HF );
+ ad_close_metadata( adp);
}
#ifdef DEBUG
LOG(log_info, logtype_afpd, "end getfilparams:");
char *path, *upath;
int creatf, did, openf, retvalue = AFP_OK;
u_int16_t vid;
- int ret;
struct path *s_path;
#ifdef DEBUG
}
upath = s_path->u_name;
- if (0 != (ret = check_name(vol, upath)))
- return ret;
/* if upath is deleted we already in trouble anyway */
if ((of = of_findname(s_path))) {
openf = O_RDWR|O_CREAT|O_EXCL;
}
- if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
+ if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
openf, 0666, adp) < 0 ) {
switch ( errno ) {
case EROFS:
return( AFPERR_EXIST );
case EACCES :
return( AFPERR_ACCESS );
+ case EDQUOT:
+ case ENOSPC :
+ return( AFPERR_DFULL );
default :
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 );
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:
/* second try with adouble open
*/
- 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 (f_bitmap & ~(1<<FILPBIT_MDATE)) {
+ if ( ad_open_metadata( upath, vol_noadouble(vol), O_CREAT, adp) < 0) {
+ LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
+ /*
+ * For some things, we don't need an adouble header:
+ * - change of modification date
+ * - UNIX privs (Bug-ID #2863424)
+ */
+ if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
+ LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
}
+ LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
isad = 0;
} else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
ad_setname(adp, path->m_name);
}
if (isad) {
- ad_flush( adp, ADFLAGS_HF );
- ad_close( adp, ADFLAGS_HF );
+ ad_flush( adp);
+ ad_close_metadata( 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 */
}
*/
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
}
/* ----------------------- */
-static __inline__ int copy_all(const int dfd, const void *buf,
+static int copy_all(const int dfd, const void *buf,
size_t buflen)
{
ssize_t cc;
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;
}
/* ----------------------------------
- * 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.
*/
int copyfile(s_vol, d_vol, src, dst, newname, adp )
const struct vol *s_vol, *d_vol;
int err = 0;
int ret_err = 0;
int adflags;
- int noadouble = vol_noadouble(d_vol);
+ int stat_result;
struct stat st;
#ifdef DEBUG
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;
}
- if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
+ 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. */
+ st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ }
+
+ if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
ret_err = errno;
ad_close( adp, adflags );
if (EEXIST != ret_err) {
}
return AFPERR_EXIST;
}
- if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
+ /* XXX if the source and the dest don't use the same resource type it's broken
+ */
+ 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) {
- deletefile(d_vol, dst, 0);
- ret_err = errno;
- goto done;
- }
- else {
- ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
- if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
- ret_err = errno;
- }
- }
-
- if (!ret_err && newname) {
+ if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
+ /* set the new name in the resource fork */
+ ad_copy_header(&add, adp);
ad_setname(&add, newname);
+ ad_flush( &add );
}
+ ad_close( adp, adflags );
- ad_flush( &add, adflags );
if (ad_close( &add, adflags ) <0) {
ret_err = errno;
- }
+ }
+
if (ret_err) {
deletefile(d_vol, dst, 0);
}
- else if (!stat(src, &st)) {
+ else if (stat_result == 0) {
/* set dest modification date to src date */
struct utimbuf ut;
- /* ADS here ? */
ut.actime = ut.modtime = st.st_mtime;
utime(dst, &ut);
/* FIXME netatalk doesn't use resource fork file date
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;
/* 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:
continue;
case EACCES:
- adp = NULL; /* maybe it's a file we no rw mode for us */
+ adp = NULL; /* maybe it's a file with no write mode for us */
break; /* was return AFPERR_ACCESS;*/
case EROFS:
return AFPERR_VLOCK;
}
break; /* from the while */
}
- /*
- * Does kFPDeleteInhibitBit (bit 8) set?
- */
- if (checkAttrib) {
- u_int16_t bshort;
-
- if (adp && (adflags & ADFLAGS_HF)) {
- ad_getattr(&ad, &bshort);
- if ((bshort & htons(ATTRBIT_NODELETE))) {
- ad_close( &ad, adflags );
- return(AFPERR_OLOCK);
- }
- }
- else if (!adp) {
- /* was EACCESS error try to get only metadata */
- ad_init(&ad, vol->v_adouble, vol->v_ad_options); /* OK */
- if ( ad_metadata( file , 0, &ad) == 0 ) {
- ad_getattr(&ad, &bshort);
- ad_close( &ad, ADFLAGS_HF );
- 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
adp = of_ad(vol, &path, &ad);
- if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
+ if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
return 0;
}
if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
- ad_flush(adp, ADFLAGS_HF);
+ ad_flush(adp);
}
- ad_close(adp, ADFLAGS_HF);
+ ad_close_metadata(adp);
}
#endif /* AD_VERSION > AD_VERSION1 */
}
/* directories are bad */
- if (S_ISDIR(path.st.st_mode))
- return AFPERR_BADTYPE;
+ if (S_ISDIR(path.st.st_mode)) {
+ /* OS9 and OSX don't return the same error code */
+ return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
+ }
memcpy(&bitmap, ibuf, sizeof(bitmap));
bitmap = ntohs( bitmap );
}
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.
*/
/* 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 */
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);
}