From 6ba00099278ecf64c81aaa6211059f29dbb5efdf Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Wed, 1 Dec 2010 10:12:16 +0100 Subject: [PATCH] Fix ad_open, ad_flush, ad_close, VFS stuff and volinfo for adouble:ea, also deactivate megatron --- bin/megatron/Makefile.am | 23 +- etc/afpd/unix.c | 10 +- etc/afpd/volume.c | 12 +- include/atalk/adouble.h | 22 +- include/atalk/ea.h | 14 + libatalk/adouble/ad_date.c | 40 +-- libatalk/adouble/ad_flush.c | 134 ++++------ libatalk/adouble/ad_lock.c | 2 +- libatalk/adouble/ad_open.c | 498 ++++++------------------------------ libatalk/util/volinfo.c | 29 +-- libatalk/vfs/Makefile.am | 2 +- libatalk/vfs/extattr.c | 118 +++++++++ libatalk/vfs/vfs.c | 413 ++++-------------------------- 13 files changed, 349 insertions(+), 968 deletions(-) diff --git a/bin/megatron/Makefile.am b/bin/megatron/Makefile.am index c93e201f..f1fa4bf7 100644 --- a/bin/megatron/Makefile.am +++ b/bin/megatron/Makefile.am @@ -1,23 +1,4 @@ # Makefile.am for bin/megatron/ -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys - -bin_PROGRAMS = megatron - -megatron_SOURCES = asingle.c hqx.c macbin.c megatron.c nad.c updcrc.c -megatron_LDADD = $(top_builddir)/libatalk/libatalk.la - -noinst_HEADERS = asingle.h megatron.h hqx.h macbin.h nad.h updcrc.h - -LINKS = unbin unhex unsingle hqx2bin single2bin macbinary binheader nadheader - -install-exec-hook: - @for LINK in $(LINKS); do \ - rm -f $(DESTDIR)$(bindir)/$$LINK; \ - $(LN_S) megatron $(DESTDIR)$(bindir)/$$LINK; \ - done - -uninstall-hook: - @for LINK in $(LINKS); do \ - rm -f $(DESTDIR)$(bindir)/$$LINK; \ - done +EXTRADIST = asingle.c hqx.c macbin.c megatron.c nad.c updcrc.c \ + asingle.h megatron.h hqx.h macbin.h nad.h updcrc.h diff --git a/etc/afpd/unix.c b/etc/afpd/unix.c index 9b68c3d4..8f1fca20 100644 --- a/etc/afpd/unix.c +++ b/etc/afpd/unix.c @@ -361,7 +361,6 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode) struct dirent *dirp; DIR *dir; mode_t hf_mode; - int osx = vol->v_adouble == AD_VERSION2_OSX; int dropbox = (vol->v_flags & AFPVOL_DROPBOX); mode |= vol->v_dperm; @@ -380,7 +379,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode) for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) { /* FIXME */ - if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) { + if (*dirp->d_name == '.') { continue; } if ( lstat( dirp->d_name, &st ) < 0 ) { @@ -389,9 +388,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode) } if (!S_ISDIR(st.st_mode)) { - int setmode = (osx && *dirp->d_name == '.')?hf_mode:mode; - - if (setfilmode(dirp->d_name, setmode, &st, vol->v_umask) < 0) { + if (setfilmode(dirp->d_name, mode, &st, vol->v_umask) < 0) { LOG(log_error, logtype_afpd, "setdirmode: chmod %s: %s",dirp->d_name, strerror(errno) ); return -1; } @@ -509,13 +506,12 @@ int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const struct stat st; struct dirent *dirp; DIR *dir; - int osx = vol->v_adouble == AD_VERSION2_OSX; if (( dir = opendir( name )) == NULL ) { return( -1 ); } for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) { - if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) { + if ( *dirp->d_name == '.') { continue; } if ( lstat( dirp->d_name, &st ) < 0 ) { diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index c8570a7e..251e2031 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -445,16 +445,10 @@ static void volset(struct vol_option *options, struct vol_option *save, else if (strcasecmp(val + 1, "xlateupper") == 0) options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER; } else if (optionok(tmp, "adouble:", val)) { - if (strcasecmp(val + 1, "v1") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION1; -#if AD_VERSION == AD_VERSION2 - else if (strcasecmp(val + 1, "v2") == 0) + if (strcasecmp(val + 1, "v2") == 0) options[VOLOPT_ADOUBLE].i_value = AD_VERSION2; - else if (strcasecmp(val + 1, "osx") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX; - else if (strcasecmp(val + 1, "sfm") == 0) - options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_SFM; -#endif + else if (strcasecmp(val + 1, "ea") == 0) + options[VOLOPT_ADOUBLE].i_value = AD_VERSION_EA; } else if (optionok(tmp, "options:", val)) { char *p; diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index 2ef328e5..056ed788 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -122,16 +122,18 @@ #error bad size for AD_DATASZ2 #endif -#define AD_DATASZ_EA (AD_HEADER_LEN + (ADEID_NUM_EA * AD_ENTRY_LEN) + ADEID_FINDERI + \ - ADEID_COMMENT + ADEID_FILEDATESI + ADEID_AFPFILEI + ADEID_PRIVID) -#if AD_DATASZ_EA != 352 +#define AD_DATASZ_EA (AD_HEADER_LEN + (ADEID_NUM_EA * AD_ENTRY_LEN) + ADEDLEN_FINDERI + \ + ADEDLEN_COMMENT + ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + ADEDLEN_PRIVID) + +#if AD_DATASZ_EA != 342 #error bad size for AD_DATASZ_EA #endif #define AD_DATASZ_MAX 1024 + #if AD_VERSION == AD_VERSION2 #define AD_DATASZ AD_DATASZ2 -#elif AD_VERSION == AD_VERSION2_EA +#elif AD_VERSION == AD_VERSION_EA #define AD_DATASZ AD_DATASZ_EA #endif @@ -149,7 +151,7 @@ typedef struct adf_lock_t { } adf_lock_t; struct ad_fd { - int adf_fd; /* -1: invalid, -2: symlink, -3: Extended Attribute */ + int adf_fd; /* -1: invalid, -2: symlink */ #ifndef HAVE_PREAD off_t adf_off; #endif @@ -163,11 +165,12 @@ struct ad_fd { /* some header protection */ #define AD_INITED 0xad494e54 /* ad"INT" */ +struct adouble; + 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 *); }; @@ -213,6 +216,9 @@ struct adouble { #define ADVOL_INVDOTS (1 << 3) /* dot files (.DS_Store) are invisible) */ #define ADVOL_NOADOUBLE (1 << 4) +extern uint32_t adv2_disk_eid[]; +#define DISK_EID(a) (adv2_disk_eid[a]) + /* lock flags */ #define ADLOCK_CLR (0) #define ADLOCK_RD (1<<0) @@ -361,9 +367,7 @@ extern int ad_setfuid (const uid_t ); extern uid_t ad_getfuid (void ); extern char *ad_dir (const char *); extern char *ad_path (const char *, int); -extern char *ad_path_osx (const char *, int); -extern char *ad_path_ads (const char *, int); -extern char *ad_path_sfm (const char *, int); +extern char *ad_path_ea (const char *, int); extern int ad_mode (const char *, int); extern int ad_mkdir (const char *, int); extern void ad_init (struct adouble *, int, int ); diff --git a/include/atalk/ea.h b/include/atalk/ea.h index 2f884e61..8f10086e 100644 --- a/include/atalk/ea.h +++ b/include/atalk/ea.h @@ -19,6 +19,20 @@ #include #endif +#if HAVE_ATTR_XATTR_H +#include +#elif HAVE_SYS_XATTR_H +#include +#endif + +#ifdef HAVE_SYS_EA_H +#include +#endif + +#ifdef HAVE_SYS_EXTATTR_H +#include +#endif + #ifdef HAVE_SOLARIS_ACLS #include #endif diff --git a/libatalk/adouble/ad_date.c b/libatalk/adouble/ad_date.c index 682a8252..ab1e0a7f 100644 --- a/libatalk/adouble/ad_date.c +++ b/libatalk/adouble/ad_date.c @@ -14,25 +14,12 @@ int ad_setdate(struct adouble *ad, if (xlate) 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)); - - } else if (ad->ad_version == AD_VERSION2) { - if (!ad_getentryoff(ad, ADEID_FILEDATESI)) - return -1; - - if (dateoff > AD_DATE_ACCESS) - return -1; - memcpy(ad_entry(ad, ADEID_FILEDATESI) + dateoff, &date, sizeof(date)); + if (!ad_getentryoff(ad, ADEID_FILEDATESI)) + return -1; - } else + if (dateoff > AD_DATE_ACCESS) return -1; + memcpy(ad_entry(ad, ADEID_FILEDATESI) + dateoff, &date, sizeof(date)); return 0; } @@ -43,23 +30,12 @@ int ad_getdate(const struct adouble *ad, int xlate = (dateoff & AD_DATE_UNIX); dateoff &= AD_DATE_MASK; - 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) { - if (!ad_getentryoff(ad, ADEID_FILEDATESI)) - return -1; - - if (dateoff > AD_DATE_ACCESS) - return -1; - memcpy(date, ad_entry(ad, ADEID_FILEDATESI) + dateoff, sizeof(u_int32_t)); + if (!ad_getentryoff(ad, ADEID_FILEDATESI)) + return -1; - } else + if (dateoff > AD_DATE_ACCESS) return -1; + memcpy(date, ad_entry(ad, ADEID_FILEDATESI) + dateoff, sizeof(u_int32_t)); if (xlate) *date = AD_DATE_TO_UNIX(*date); diff --git a/libatalk/adouble/ad_flush.c b/libatalk/adouble/ad_flush.c index 1f4d8b33..a6235775 100644 --- a/libatalk/adouble/ad_flush.c +++ b/libatalk/adouble/ad_flush.c @@ -1,5 +1,6 @@ /* * Copyright (c) 1990,1991 Regents of The University of Michigan. + * Copyright (c) 2010 Frank Lahm * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and @@ -26,42 +27,27 @@ #endif /* HAVE_CONFIG_H */ #include -#include - #include #include #include -#include "ad_private.h" -#if AD_VERSION == AD_VERSION1 - -#define EID_DISK(a) (a) - -#else - -static const u_int32_t set_eid[] = { - 0,1,2,3,4,5,6,7,8, - 9,10,11,12,13,14,15, - AD_DEV, AD_INO, AD_SYN, AD_ID -}; +#include +#include +#include -#define EID_DISK(a) (set_eid[a]) -#endif +#include "ad_private.h" -/* rebuild the adouble header - * XXX should be in a separate file ? +/* + * Rebuild any header information that might have changed. */ int ad_rebuild_adouble_header(struct adouble *ad) { u_int32_t eid; u_int32_t temp; - u_int16_t nent; char *buf, *nentp; + int len; - /* - * Rebuild any header information that might have changed. - */ buf = ad->ad_data; temp = htonl( ad->ad_magic ); @@ -72,16 +58,13 @@ int ad_rebuild_adouble_header(struct adouble *ad) memcpy(buf, &temp, sizeof( temp )); buf += sizeof( temp ); - memcpy(buf, ad->ad_filler, sizeof( ad->ad_filler )); - buf += sizeof( ad->ad_filler ); - nentp = buf; buf += sizeof( nent ); for ( eid = 0, nent = 0; eid < ADEID_MAX; eid++ ) { if ( ad->ad_eid[ eid ].ade_off == 0 ) { continue; } - temp = htonl( EID_DISK(eid) ); + temp = htonl( DISK_EID(eid) ); memcpy(buf, &temp, sizeof( temp )); buf += sizeof( temp ); @@ -96,7 +79,21 @@ int ad_rebuild_adouble_header(struct adouble *ad) } nent = htons( nent ); memcpy(nentp, &nent, sizeof( nent )); - return ad_getentryoff(ad, ADEID_RFORK); + + switch (ad->ad_version) { + case AD_VERSION2: + len = ad_getentryoff(ad, ADEID_RFORK); + break; + case AD_VERSION_EA: + len = AD_DATASZ_EA; + break; + default: + LOG(log_error, logtype_afpd, "Unexpected adouble version"); + len = 0; + break; + } + + return len; } /* ------------------- @@ -134,57 +131,36 @@ int ad_copy_header(struct adouble *add, struct adouble *ads) return 0; } -/* ------------------- */ -int ad_rebuild_sfm_header(struct adouble *ad) -{ - u_int32_t temp; - - u_int16_t attr; - char *buf; - - /* - * 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( struct adouble *ad) +int ad_flush(struct adouble *ad) { int len; if (( ad->ad_md->adf_flags & O_RDWR )) { - /* sync our header */ - if (ad->ad_rlen > 0xffffffff) { - ad_setentrylen(ad, ADEID_RFORK, 0xffffffff); - } - else { - ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen); + if (ad_getentryoff(ad, ADEID_RFORK)) { + if (ad->ad_rlen > 0xffffffff) + ad_setentrylen(ad, ADEID_RFORK, 0xffffffff); + else + ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen); } 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; + switch (ad->ad_version) { + case AD_VERSION2: + if (adf_pwrite(ad->ad_md, ad->ad_data, len, 0) != len) { + if (errno == 0) + errno = EIO; + return( -1 ); + } + break; + case AD_VERSION_EA: + if (sys_fsetxattr(ad->ad_md->adf_fd, AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) != 0) { + LOG(log_error, logtype_afpd, "Unexpected adouble version"); + return -1; } - return( -1 ); + break; + default: + LOG(log_error, logtype_afpd, "Unexpected adouble version"); + return -1; } } @@ -214,7 +190,7 @@ int ad_close( struct adouble *ad, int adflags) return err; } - /* meta /resource fork */ + /* meta/resource fork */ if ( ad_meta_fileno(ad) != -1 && !(--ad->ad_md->adf_refcount)) { if ( close( ad_meta_fileno(ad) ) < 0 ) { @@ -224,21 +200,5 @@ int ad_close( struct adouble *ad, int adflags) adf_lock_free(ad->ad_md); } - 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 30a13033..688ec4b9 100644 --- a/libatalk/adouble/ad_lock.c +++ b/libatalk/adouble/ad_lock.c @@ -632,7 +632,7 @@ void ad_fcntl_unlock(struct adouble *ad, const int fork) adf_unlock(&ad->ad_resource_fork, fork); } - if (ad->ad_flags != AD_VERSION1_SFM) { + if (ad->ad_flags != AD_VERSION_EA) { return; } if (ad_meta_fileno(ad) != -1) { diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 7806f821..ba88b5d7 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "ad_private.h" @@ -96,15 +97,11 @@ #undef ADEDOFF_FILEI #endif /* ADEDOFF_FILEI */ -#define ADEDOFF_NAME_V1 (AD_HEADER_LEN + ADEID_NUM_V1*AD_ENTRY_LEN) -#define ADEDOFF_COMMENT_V1 (ADEDOFF_NAME_V1 + ADEDLEN_NAME) -#define ADEDOFF_FILEI (ADEDOFF_COMMENT_V1 + ADEDLEN_COMMENT) -#define ADEDOFF_FINDERI_V1 (ADEDOFF_FILEI + ADEDLEN_FILEI) -#define ADEDOFF_RFORK_V1 (ADEDOFF_FINDERI_V1 + ADEDLEN_FINDERI) - /* i stick things in a slightly different order than their eid order in * case i ever want to separate RootInfo behaviour from the rest of the * stuff. */ + +/* ad:v2 */ #define ADEDOFF_NAME_V2 (AD_HEADER_LEN + ADEID_NUM_V2*AD_ENTRY_LEN) #define ADEDOFF_COMMENT_V2 (ADEDOFF_NAME_V2 + ADEDLEN_NAME) #define ADEDOFF_FILEDATESI (ADEDOFF_COMMENT_V2 + ADEDLEN_COMMENT) @@ -119,15 +116,14 @@ #define ADEDOFF_PRIVID (ADEDOFF_PRIVSYN + ADEDLEN_PRIVSYN) #define ADEDOFF_RFORK_V2 (ADEDOFF_PRIVID + ADEDLEN_PRIVID) -#define ADEDOFF_FINDERI_OSX (AD_HEADER_LEN + ADEID_NUM_OSX*AD_ENTRY_LEN) -#define ADEDOFF_RFORK_OSX (ADEDOFF_FINDERI_OSX + ADEDLEN_FINDERI) - -/* we keep local copies of a bunch of stuff so that we can initialize things - * correctly. */ +/* ad:ea */ +#define ADEDOFF_FINDERI_EA (AD_HEADER_LEN + ADEID_NUM_EA * AD_ENTRY_LEN) +#define ADEDOFF_COMMENT_EA (ADEDOFF_FINDERI_EA + ADEDLEN_FINDERI) +#define ADEDOFF_FILEDATESI_EA (ADEDOFF_COMMENT_EA + ADEDLEN_COMMENT) +#define ADEDOFF_AFPFILEI_EA (ADEDOFF_FILEDATESI_EA + ADEDLEN_FILEDATESI) /* this is to prevent changing timezones from causing problems with - localtime volumes. the screw-up is 30 years. we use a delta of 5 - years. */ + localtime volumes. the screw-up is 30 years. we use a delta of 5 years */ #define TIMEWARP_DELTA 157680000 struct entry { @@ -137,68 +133,61 @@ struct entry { /* --------------------------- */ static uid_t default_uid = -1; +/* Forward declarations */ +static int ad_mkrf(char *path); +static int ad_header_read(struct adouble *ad, struct stat *hst); +static int ad_header_upgrade(struct adouble *ad, char *name); + +static int ad_mkrf_ea(char *path); +static int ad_header_read_ea(struct adouble *ad, struct stat *hst); +static int ad_header_upgrade_ea(struct adouble *ad, char *name); + static struct adouble_fops ad_adouble = { &ad_path, &ad_mkrf, &ad_rebuild_adouble_header, - &ad_check_size, &ad_header_read, &ad_header_upgrade, }; static struct adouble_fops ad_adouble_ea = { - &ad_path, - &ad_mkrf, + &ad_path_ea, + &ad_mkrf_ea, &ad_rebuild_adouble_header, - &ad_check_size, &ad_header_read_ea, &ad_header_upgrade_ea, }; static const struct entry entry_order2[ADEID_NUM_V2 + 1] = { - {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT}, - {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT}, - {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI}, - {ADEID_FINDERI, ADEDOFF_FINDERI_V2, ADEDLEN_FINDERI}, - {ADEID_DID, ADEDOFF_DID, ADEDLEN_DID}, - {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI}, - {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT}, + {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT}, + {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT}, + {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI}, + {ADEID_FINDERI, ADEDOFF_FINDERI_V2, ADEDLEN_FINDERI}, + {ADEID_DID, ADEDOFF_DID, ADEDLEN_DID}, + {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI}, + {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT}, {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI}, - {ADEID_PRIVDEV, ADEDOFF_PRIVDEV, ADEDLEN_INIT}, - {ADEID_PRIVINO, ADEDOFF_PRIVINO, ADEDLEN_INIT}, - {ADEID_PRIVSYN, ADEDOFF_PRIVSYN, ADEDLEN_INIT}, - {ADEID_PRIVID, ADEDOFF_PRIVID, ADEDLEN_INIT}, - {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT}, + {ADEID_PRIVDEV, ADEDOFF_PRIVDEV, ADEDLEN_INIT}, + {ADEID_PRIVINO, ADEDOFF_PRIVINO, ADEDLEN_INIT}, + {ADEID_PRIVSYN, ADEDOFF_PRIVSYN, ADEDLEN_INIT}, + {ADEID_PRIVID, ADEDOFF_PRIVID, ADEDLEN_INIT}, + {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT}, {0, 0, 0} }; /* Using Extended Attributes */ static const struct entry entry_order_ea[ADEID_NUM_EA + 1] = { - {ADEID_FINDERI, ADEDOFF_FINDERI_OSX, ADEDLEN_FINDERI}, - {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT}, - {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI}, - {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI}, - {ADEID_PRIVID, ADEDOFF_PRIVID, ADEDLEN_INIT}, + {ADEID_FINDERI, ADEDOFF_FINDERI_EA, ADEDLEN_FINDERI}, + {ADEID_COMMENT, ADEDOFF_COMMENT_EA, ADEDLEN_INIT}, + {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_EA, ADEDLEN_FILEDATESI}, + {ADEID_AFPFILEI, ADEDOFF_AFPFILEI_EA, ADEDLEN_AFPFILEI}, {0, 0, 0} }; -#define DISK_EID(ad, a) get_eid(ad, a) - -static uint32_t get_eid(struct adouble *ad, u_int32_t eid) -{ - if (eid <= 15) - return eid; - if (eid == AD_DEV) - return ADEID_PRIVDEV; - if (eid == AD_INO) - return ADEID_PRIVINO; - if (eid == AD_SYN) - return ADEID_PRIVSYN; - if (eid == AD_ID) - return ADEID_PRIVID; - - return 0; -} +uint32_t adv2_disk_eid[] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + AD_DEV, AD_INO, AD_SYN, AD_ID +}; /* ----------------------------------- */ static int new_ad_header(const char *path, struct adouble *ad, int adflags) @@ -242,7 +231,7 @@ static int new_ad_header(const char *path, struct adouble *ad, int adflags) } /* make things invisible */ - if ((ad->ad_options & ADVOL_INVDOTS) && (adflags & ADFLAGS_CREATE) && (*path == '.')) { + if ((ad->ad_options & ADVOL_INVDOTS) && (*path == '.')) { ashort = htons(ATTRBIT_INVISIBLE); ad_setattr(ad, ashort); ashort = htons(FINDERINFO_INVISIBLE); @@ -260,287 +249,6 @@ static int new_ad_header(const char *path, struct adouble *ad, int adflags) return 0; } -/* update a version 2 adouble resource fork with our private entries */ -static int ad_update(struct adouble *ad, const char *path) -{ - struct stat st; - u_int16_t nentries = 0; - off_t off, shiftdata=0; - const struct entry *eid; - static off_t entry_len[ADEID_MAX]; - static char databuf[ADEID_MAX][256], *buf; - int fd; - int ret = -1; - - /* check to see if we should convert this header. */ - if (!path || ad->ad_flags != AD_VERSION2) - return 0; - - LOG(log_maxdebug, logtype_default, "ad_update: checking whether '%s' needs an upgrade.", path); - - if (!(ad->ad_md->adf_flags & O_RDWR)) { - /* we were unable to open the file read write the last time */ - return 0; - } - - if (ad->ad_eid[ADEID_RFORK].ade_off) { - shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off; - } - - memcpy(&nentries, ad->ad_data + ADEDOFF_NENTRIES, sizeof( nentries )); - nentries = ntohs( nentries ); - - if ( shiftdata == 0 && nentries == ADEID_NUM_V2) - return 0; - - memset(entry_len, 0, sizeof(entry_len)); - memset(databuf, 0, sizeof(databuf)); - - /* bail if we can't get a lock */ - if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0) - goto bail_err; - - fd = ad->ad_md->adf_fd; - - if (fstat(fd, &st)) { - goto bail_lock; - } - - if (st.st_size > 0x7fffffff) { - LOG(log_debug, logtype_default, "ad_update: file '%s' too big for update.", path); - errno = EIO; - goto bail_lock; - } - - off = ad->ad_eid[ADEID_RFORK].ade_off; - if (off > st.st_size) { - LOG(log_error, logtype_default, "ad_update: invalid resource fork offset. (off: %u)", off); - errno = EIO; - goto bail_lock; - } - - if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) { - LOG(log_error, logtype_default, "ad_update: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len); - errno = EIO; - goto bail_lock; - } - - if ((void *) (buf = (char *) - mmap(NULL, st.st_size + shiftdata, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == - MAP_FAILED) { - goto bail_lock; - } - - /* last place for failure. */ - if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) { - munmap(buf, st.st_size + shiftdata); - goto bail_lock; - } - - /* move the RFORK. this assumes that the RFORK is at the end */ - if (off) { - memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len); - } - - munmap(buf, st.st_size + shiftdata); - - /* now, fix up our copy of the header */ - memset(ad->ad_filler, 0, sizeof(ad->ad_filler)); - - /* save the header entries */ - eid = entry_order2; - while (eid->id) { - if( ad->ad_eid[eid->id].ade_off != 0) { - if ( eid->id > 2 && ad->ad_eid[eid->id].ade_len < 256) - memcpy( databuf[eid->id], ad->ad_data +ad->ad_eid[eid->id].ade_off, ad->ad_eid[eid->id].ade_len); - entry_len[eid->id] = ad->ad_eid[eid->id].ade_len; - } - eid++; - } - - memset(ad->ad_data + AD_HEADER_LEN, 0, AD_DATASZ - AD_HEADER_LEN); - - /* copy the saved entries to the new header */ - eid = entry_order2; - while (eid->id) { - if ( eid->id > 2 && entry_len[eid->id] > 0) { - memcpy(ad->ad_data+eid->offset, databuf[eid->id], entry_len[eid->id]); - } - ad->ad_eid[eid->id].ade_off = eid->offset; - ad->ad_eid[eid->id].ade_len = entry_len[eid->id]; - eid++; - } - - /* rebuild the header and cleanup */ - LOG(log_debug, logtype_default, "updated AD2 header %s", path); - ad_flush(ad ); - ret = 0; - -bail_lock: - ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0); -bail_err: - return ret; -} - -/* ------------------------------------------ - FIXME work only if < 2GB -*/ -static int ad_convert(struct adouble *ad, const char *path) -{ - struct stat st; - u_int16_t attr; - char *buf; - int fd, off; - int ret = -1; - /* use resource fork offset from file */ - int shiftdata; - int toV2; - int toV1; - - if (!path) { - return 0; - } - - if (!(ad->ad_md->adf_flags & ( O_RDWR))) { - /* we were unable to open the file read write the last time */ - return 0; - } - - /* check to see if we should convert this header. */ - toV2 = ad->ad_version == AD_VERSION1 && ad->ad_flags == AD_VERSION2; - toV1 = ad->ad_version == AD_VERSION2 && ad->ad_flags == AD_VERSION1; - - if (!toV2 && !toV1) - return 0; - - /* convert from v1 to v2. what does this mean? - * 1) change FILEI into FILEDATESI - * 2) create space for SHORTNAME, AFPFILEI, DID, and PRODOSI - * 3) move FILEI attributes into AFPFILEI - * 4) initialize ACCESS field of FILEDATESI. - * 5) move the resource fork - */ - - /* bail if we can't get a lock */ - if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0) - goto bail_err; - - /* we reuse fd from the resource fork */ - 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; - } - else { - shiftdata = ADEDOFF_RFORK_V2 -ADEDOFF_RFORK_V1; /* 136 */ - } - - if (fstat(fd, &st)) { - goto bail_lock; - } - - if (st.st_size > 0x7fffffff -shiftdata) { - LOG(log_debug, logtype_default, "ad_v1tov2: file too big."); - errno = EIO; - goto bail_lock; - } - - off = ad->ad_eid[ADEID_RFORK].ade_off; - - if (off > st.st_size) { - LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork offset. (off: %u)", off); - errno = EIO; - goto bail_lock; - } - - if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) { - LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len); - errno = EIO; - goto bail_lock; - } - - if ((void *) (buf = (char *) - mmap(NULL, st.st_size + shiftdata, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == - MAP_FAILED) { - goto bail_lock; - } - - /* last place for failure. */ - - if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) { - goto bail_lock; - } - - /* move the RFORK. this assumes that the RFORK is at the end */ - if (off) { - memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len); - } - - munmap(buf, st.st_size + shiftdata); - - /* now, fix up our copy of the header */ - memset(ad->ad_filler, 0, sizeof(ad->ad_filler)); - - /* replace FILEI with FILEDATESI */ - ad_getattr(ad, &attr); - ad->ad_eid[ADEID_FILEDATESI].ade_off = ADEDOFF_FILEDATESI; - ad->ad_eid[ADEID_FILEDATESI].ade_len = ADEDLEN_FILEDATESI; - ad->ad_eid[ADEID_FILEI].ade_off = 0; - ad->ad_eid[ADEID_FILEI].ade_len = 0; - - /* add in the new entries */ - ad->ad_eid[ADEID_DID].ade_off = ADEDOFF_DID; - ad->ad_eid[ADEID_DID].ade_len = ADEDLEN_DID; - ad->ad_eid[ADEID_AFPFILEI].ade_off = ADEDOFF_AFPFILEI; - ad->ad_eid[ADEID_AFPFILEI].ade_len = ADEDLEN_AFPFILEI; - ad->ad_eid[ADEID_SHORTNAME].ade_off = ADEDOFF_SHORTNAME; - ad->ad_eid[ADEID_SHORTNAME].ade_len = ADEDLEN_INIT; - ad->ad_eid[ADEID_PRODOSFILEI].ade_off = ADEDOFF_PRODOSFILEI; - ad->ad_eid[ADEID_PRODOSFILEI].ade_len = ADEDLEN_PRODOSFILEI; - - ad->ad_eid[ADEID_PRIVDEV].ade_off = ADEDOFF_PRIVDEV; - ad->ad_eid[ADEID_PRIVDEV].ade_len = ADEDLEN_INIT; - ad->ad_eid[ADEID_PRIVINO].ade_off = ADEDOFF_PRIVINO; - ad->ad_eid[ADEID_PRIVINO].ade_len = ADEDLEN_INIT; - ad->ad_eid[ADEID_PRIVSYN].ade_off = ADEDOFF_PRIVSYN; - ad->ad_eid[ADEID_PRIVSYN].ade_len = ADEDLEN_INIT; - ad->ad_eid[ADEID_PRIVID].ade_off = ADEDOFF_PRIVID; - ad->ad_eid[ADEID_PRIVID].ade_len = ADEDLEN_INIT; - - /* shift the old entries (NAME, COMMENT, FINDERI, RFORK) */ - ad->ad_eid[ADEID_NAME].ade_off = ADEDOFF_NAME_V2; - ad->ad_eid[ADEID_COMMENT].ade_off = ADEDOFF_COMMENT_V2; - ad->ad_eid[ADEID_FINDERI].ade_off = ADEDOFF_FINDERI_V2; - ad->ad_eid[ADEID_RFORK].ade_off = ADEDOFF_RFORK_V2; - - /* switch to dest version */ - ad->ad_version = (toV2)?AD_VERSION2:AD_VERSION1; - - /* move our data buffer to make space for the new entries. */ - memmove(ad->ad_data + ADEDOFF_NAME_V2, ad->ad_data + ADEDOFF_NAME_V1, - ADEDOFF_RFORK_V1 - ADEDOFF_NAME_V1); - - /* now, fill in the space with appropriate stuff. we're - operating as a v2 file now. */ - ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime); - memset(ad_entry(ad, ADEID_DID), 0, ADEDLEN_DID); - memset(ad_entry(ad, ADEID_AFPFILEI), 0, ADEDLEN_AFPFILEI); - ad_setattr(ad, attr); - memset(ad_entry(ad, ADEID_SHORTNAME), 0, ADEDLEN_SHORTNAME); - memset(ad_entry(ad, ADEID_PRODOSFILEI), 0, ADEDLEN_PRODOSFILEI); - - /* rebuild the header and cleanup */ - ad_flush(ad ); - ret = 0; - -bail_lock: - ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0); -bail_err: - return ret; -} - /* ------------------------------------- read in the entries */ @@ -552,7 +260,7 @@ static void parse_entries(struct adouble *ad, char *buf, uint16_t nentries) /* now, read in the entry bits */ for (; nentries > 0; nentries-- ) { memcpy(&eid, buf, sizeof( eid )); - eid = DISK_EID(ad, ntohl( eid )); + eid = DISK_EID(ntohl( eid )); buf += sizeof( eid ); memcpy(&off, buf, sizeof( off )); off = ntohl( off ); @@ -585,7 +293,6 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) u_int16_t nentries; int len; ssize_t header_len; - static int warning = 0; struct stat st; /* read the header */ @@ -600,37 +307,12 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic )); memcpy(&ad->ad_version, buf + ADEDOFF_VERSION, sizeof( ad->ad_version )); - /* tag broken v1 headers. just assume they're all right. - * we detect two cases: null magic/version - * byte swapped magic/version - * XXX: in the future, you'll need the v1compat flag. */ - if (!ad->ad_magic && !ad->ad_version) { - if (!warning) { - LOG(log_debug, logtype_default, "notice: fixing up null v1 magic/version."); - warning++; - } - ad->ad_magic = AD_MAGIC; - ad->ad_version = AD_VERSION1; - - } else if (ad->ad_magic == AD_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 ); - } - - if ((ad->ad_magic != AD_MAGIC) || - ((ad->ad_version != AD_VERSION1) && (ad->ad_version != AD_VERSION2))) { + if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) { LOG(log_error, logtype_default, "ad_open: can't parse AppleDouble header."); errno = EIO; return -1; } - memcpy(ad->ad_filler, buf + ADEDOFF_FILLER, sizeof( ad->ad_filler )); memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries )); nentries = ntohs( nentries ); @@ -677,16 +359,14 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) return 0; } -static int ad_header_read_ea(struct adouble *ad, struct stat *hst) +static int ad_header_read_ea(struct adouble *ad, struct stat *hst _U_) { - uint16_t nentries; - int len; - ssize_t header_len; - static int warning = 0; - struct stat st; - + uint16_t nentries; + int len; + ssize_t header_len; + char *buf = ad->ad_data; /* read the header */ - if ((header_len = sys_lgetxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA)) < 0) { + if ((header_len = sys_fgetxattr(ad->ad_md->adf_fd, AD_EA_META, ad->ad_data, AD_DATASZ_EA)) < 0) { LOG(log_error, logtype_default, "ad_open: can't parse AppleDouble header."); errno = EIO; return -1; @@ -725,6 +405,7 @@ static int ad_header_read_ea(struct adouble *ad, struct stat *hst) /* Now parse entries */ parse_entries(ad, buf + AD_HEADER_LEN, nentries); + return 0; } static int ad_mkrf(char *path) @@ -745,6 +426,11 @@ static int ad_mkrf(char *path) return 0; } +static int ad_mkrf_ea(char *path _U_) +{ + AFP_PANIC("ad_mkrf_ea: dont use"); + return 0; +} /* ---------------- if we are root change path user/ group @@ -771,6 +457,8 @@ static int ad_chown(const char *path, struct stat *stbuf) return ret; } +#define DEFMASK 07700 /* be conservative */ + /* ---------------- return access right and inode of path parent directory */ @@ -803,43 +491,20 @@ static int ad_error(struct adouble *ad, int adflags) } /* --------------------------- */ -static int ad_check_size(struct adouble *ad _U_, struct stat *st) +static int ad_header_upgrade(struct adouble *ad _U_, char *name _U_) { - if (st->st_size > 0 && st->st_size < AD_DATASZ1) - return 1; return 0; } -/* --------------------------- */ -static int ad_check_size_sfm(struct adouble *ad _U_, 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) -{ - int ret; - if ( (ret = ad_convert(ad, name)) < 0 || (ret = ad_update(ad, name) < 0)) { - return ret; - } - return 0; -} - -/* --------------------------- */ -static int ad_header_upgrade_none(struct adouble *ad _U_, char *name _U_) +static int ad_header_upgrade_ea(struct adouble *ad _U_, char *name _U_) { + AFP_PANIC("ad_header_upgrade_ea: dont use"); return 0; } static int ad_open_df(const char *path, int adflags, int oflags, int mode, struct adouble *ad) { struct stat st_dir; - struct stat st_meta; - struct stat *pst = NULL; - char *ad_p; int hoflags, admode; int st_invalid = -1; @@ -980,8 +645,6 @@ static int ad_open_hf_v2(const char *path, int adflags, int oflags, int mode, st } AD_SET(ad->ad_md->adf_off); - ad->ad_md->adf_refcount = 1; - adf_lock_init(ad->ad_md); if ((ad->ad_md->adf_flags & ( O_TRUNC | O_CREAT ))) { /* This is a new adouble header file, create it */ if (new_ad_header(path, ad, adflags) < 0) { @@ -1008,10 +671,15 @@ static int ad_open_hf_v2(const char *path, int adflags, int oflags, int mode, st static int ad_open_hf_ea(const char *path, int adflags, int oflags, int mode, struct adouble *ad) { - ad->ad_md->adf_fd = -3; + int hoflags; + ssize_t rforklen; + + hoflags = (oflags & ~(O_CREAT | O_EXCL)) | O_NOFOLLOW; + if ((ad->ad_md->adf_fd = open(path, hoflags)) == -1) + return -1; /* Read the adouble header in and parse it.*/ - if (ad->ad_ops->ad_header_read(ad, path) != 0) { + if (ad->ad_ops->ad_header_read(ad, NULL) != 0) { /* It doesnt exist, EPERM or another error */ if (errno != ENOENT) return -1; @@ -1027,8 +695,12 @@ static int ad_open_hf_ea(const char *path, int adflags, int oflags, int mode, st ad_flush(ad); } - ssize_t rforklen = - + if ((rforklen = sys_lgetxattr(path, AD_EA_RESO, NULL, 0)) < 0) { + rforklen = 0; + } + + ad->ad_rlen = rforklen; + return 0; } static int ad_open_hf(const char *path, int adflags, int oflags, int mode, struct adouble *ad) @@ -1055,7 +727,7 @@ static int ad_open_hf(const char *path, int adflags, int oflags, int mode, struc ad->ad_rlen = 0; switch (ad->ad_version) { - case AD_VERSION_2: + case AD_VERSION2: ret = ad_open_hf_v2(path, adflags, oflags, mode, ad); break; case AD_VERSION_EA: @@ -1066,6 +738,9 @@ static int ad_open_hf(const char *path, int adflags, int oflags, int mode, struc break; } + ad->ad_md->adf_refcount = 1; + adf_lock_init(ad->ad_md); + return ret; } @@ -1078,6 +753,11 @@ static int ad_open_rf(const char *path, int adflags, int oflags, int mode, struc * API functions ********************************************************************************* */ +char *ad_path_ea( const char *path, int adflags _U_) +{ + return path; +} + /* * Put the .AppleDouble where it needs to be: * @@ -1124,9 +804,6 @@ char *ad_path( const char *path, int adflags) * mode is ANDed with the parent directory's mask value in lieu of "umask", * and that value is returned. */ - -#define DEFMASK 07700 /* be conservative */ - char *ad_dir(const char *path) { static char modebuf[ MAXPATHLEN + 1]; @@ -1272,7 +949,6 @@ void ad_init(struct adouble *ad, int flags, int options) * @param adflags ADFLAGS_DF: open data fork \n * ADFLAGS_RF: open ressource fork \n * ADFLAGS_HF: open header (metadata) file \n - * ADFLAGS_CREATE: indicate creation \n * ADFLAGS_NOHF: it's not an error if header file couldn't be created \n * ADFLAGS_DIR: if path is a directory you MUST or ADFLAGS_DIR to adflags \n * ADFLAGS_NOADOUBLE: dont create adouble files if not necessary \n @@ -1296,14 +972,6 @@ void ad_init(struct adouble *ad, int flags, int options) */ int ad_open(const char *path, int adflags, int oflags, int mode, struct adouble *ad) { - 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->ad_inited = AD_INITED; ad->ad_refcount = 1; @@ -1433,7 +1101,7 @@ exit: int ad_refresh(struct adouble *ad) { - if (ad_meta_fileno(ad) < 0) + if (ad_meta_fileno(ad) == -1) return -1; return ad->ad_ops->ad_header_read(ad, NULL); diff --git a/libatalk/util/volinfo.c b/libatalk/util/volinfo.c index d4fdfab0..3e639f09 100644 --- a/libatalk/util/volinfo.c +++ b/libatalk/util/volinfo.c @@ -300,21 +300,14 @@ static int parseline ( char *buf, struct volinfo *vol) } break; case ADOUBLE_VER: - if (strcasecmp(value, "v1") == 0) { - vol->v_adouble = AD_VERSION1; - vol->ad_path = ad_path; - } -#if AD_VERSION == AD_VERSION2 - else if (strcasecmp(value, "v2") == 0) { + if (strcasecmp(value, "v2") == 0) { vol->ad_path = ad_path; vol->v_adouble = AD_VERSION2; - } - else if (strcasecmp(value, "osx") == 0) { - vol->v_adouble = AD_VERSION2_OSX; - vol->ad_path = ad_path_osx; - } -#endif - else { + } else if (strcasecmp(value, "ea") == 0) { + vol->ad_path = ad_path_ea; + vol->v_adouble = AD_VERSION_EA; + } else { + fprintf (stderr, "unknown adouble version: %s, %s", buf, value); return -1; } @@ -455,17 +448,11 @@ int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_po strlcat(buf, item, sizeof(buf)); switch (vol->v_adouble) { - case AD_VERSION1: - strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf)); - break; case AD_VERSION2: strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf)); break; - case AD_VERSION2_OSX: - strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf)); - break; - case AD_VERSION1_SFM: - strlcat(buf, "ADOUBLE_VER:sfm\n", sizeof(buf)); + case AD_VERSION_EA: + strlcat(buf, "ADOUBLE_VER:ea\n", sizeof(buf)); break; } diff --git a/libatalk/vfs/Makefile.am b/libatalk/vfs/Makefile.am index 639f51b3..aa62aebf 100644 --- a/libatalk/vfs/Makefile.am +++ b/libatalk/vfs/Makefile.am @@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libvfs.la -libvfs_la_SOURCES = vfs.c unix.c extattr.c ea_ad.c ea_sys.c +libvfs_la_SOURCES = vfs.c unix.c ea_ad.c ea_sys.c extattr.c if HAVE_ACLS libvfs_la_SOURCES += acl.c diff --git a/libatalk/vfs/extattr.c b/libatalk/vfs/extattr.c index 76b435c8..35587a6e 100644 --- a/libatalk/vfs/extattr.c +++ b/libatalk/vfs/extattr.c @@ -149,6 +149,59 @@ ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t s #endif } +ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size) +{ +#if defined(HAVE_FGETXATTR) +#ifndef XATTR_ADD_OPT + return fgetxattr(filedes, name, value, size); +#else + int options = 0; + return fgetxattr(filedes, name, value, size, 0, options); +#endif +#elif defined(HAVE_FGETEA) + return fgetea(filedes, name, value, size); +#elif defined(HAVE_EXTATTR_GET_FD) + char *s; + ssize_t retval; + int attrnamespace = (strncmp(name, "system", 6) == 0) ? + EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; + const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1; + + if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) { + if(retval > size) { + errno = ERANGE; + return -1; + } + if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0) + return retval; + } + + DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno))); + return -1; +#elif defined(HAVE_ATTR_GETF) + int retval, flags = 0; + int valuelength = (int)size; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; + + retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags); + + return retval ? retval : valuelength; +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0); + if (attrfd >= 0) { + ret = solaris_read_xattr(attrfd, value, size); + close(attrfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size) { const char *name = prefix(uname); @@ -577,6 +630,71 @@ int sys_setxattr (const char *path, const char *uname, const void *value, size_t #endif } +int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags) +{ +#if defined(HAVE_FSETXATTR) +#ifndef XATTR_ADD_OPT + return fsetxattr(filedes, name, value, size, flags); +#else + int options = 0; + return fsetxattr(filedes, name, value, size, 0, options); +#endif +#elif defined(HAVE_FSETEA) + return fsetea(filedes, name, value, size, flags); +#elif defined(HAVE_EXTATTR_SET_FD) + char *s; + int retval = 0; + int attrnamespace = (strncmp(name, "system", 6) == 0) ? + EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; + const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1; + if (flags) { + /* Check attribute existence */ + retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0); + if (retval < 0) { + /* REPLACE attribute, that doesn't exist */ + if (flags & XATTR_REPLACE && errno == ENOATTR) { + errno = ENOATTR; + return -1; + } + /* Ignore other errors */ + } + else { + /* CREATE attribute, that already exists */ + if (flags & XATTR_CREATE) { + errno = EEXIST; + return -1; + } + } + } + retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size); + return (retval < 0) ? -1 : 0; +#elif defined(HAVE_ATTR_SETF) + int myflags = 0; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; + if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; + if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; + + return attr_setf(filedes, attrname, (const char *)value, size, myflags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int myflags = O_RDWR | O_XATTR; + int attrfd; + if (flags & XATTR_CREATE) myflags |= O_EXCL; + if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; + attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE); + if (attrfd >= 0) { + ret = solaris_write_xattr(attrfd, value, size); + close(attrfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags) { const char *name = prefix(uname); diff --git a/libatalk/vfs/vfs.c b/libatalk/vfs/vfs.c index 3156afe3..57a4e0c2 100644 --- a/libatalk/vfs/vfs.c +++ b/libatalk/vfs/vfs.c @@ -493,368 +493,71 @@ EC_CLEANUP: } #endif -/********************************************************************************* - * sfm adouble format - *********************************************************************************/ -static int ads_chown_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_) -{ - struct perm *owner = data; - - if (chown( name , owner->uid, owner->gid ) < 0) { - return -1; - } - return 0; -} - -static int RF_chown_ads(VFS_FUNC_ARGS_CHOWN) -{ - struct stat st; - char *ad_p; - struct perm owner; - - owner.uid = uid; - owner.gid = gid; - - - ad_p = ad_dir(vol->ad_path(path, ADFLAGS_HF )); - - if ( stat( ad_p, &st ) < 0 ) { - /* ignore */ - return 0; - } - - if (chown( ad_p, uid, gid ) < 0) { - return -1; - } - return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1, vol->v_umask); -} - -/* --------------------------------- */ -static int deletecurdir_ads1_loop(struct dirent *de _U_, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_) -{ - return netatalk_unlink(name); -} - -static int ads_delete_rf(char *name) -{ - int err; - - if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0))) - return err; - /* FIXME - * it's a problem for a nfs mounted folder, there's .nfsxxx around - * for linux the following line solve it. - * but it could fail if rm .nfsxxx create a new .nfsyyy :( - */ - if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0))) - return err; - return netatalk_rmdir(-1, name); -} - -static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_) -{ - struct stat st; - - /* bail if the file exists in the current directory. - * note: this will not fail with dangling symlinks */ - - if (stat(de->d_name, &st) == 0) { - return AFPERR_DIRNEMPT; - } - return ads_delete_rf(name); -} - -static int RF_deletecurdir_ads(VFS_FUNC_ARGS_DELETECURDIR) -{ - int err; - - /* delete stray .AppleDouble files. this happens to get .Parent files as well. */ - if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1, 0))) - return err; - - return netatalk_rmdir(-1, ".AppleDouble" ); -} - -/* ------------------- */ -struct set_mode { - mode_t mode; - struct stat *st; -}; - -static int ads_setfilmode_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask) +/************************************************************************* + * EA adouble format + ************************************************************************/ +static int validupath_ea(VFS_FUNC_ARGS_VALIDUPATH) { - struct set_mode *param = data; - - return setfilmode(name, param->mode, param->st, v_umask); -} + return 1; +} -static int ads_setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask) +/* ----------------- */ +static int RF_chown_ea(VFS_FUNC_ARGS_CHOWN) { - mode_t file_mode = ad_hf_mode(mode); - mode_t dir_mode = file_mode; - struct set_mode param; - - if ((dir_mode & (S_IRUSR | S_IWUSR ))) - dir_mode |= S_IXUSR; - if ((dir_mode & (S_IRGRP | S_IWGRP ))) - dir_mode |= S_IXGRP; - if ((dir_mode & (S_IROTH | S_IWOTH ))) - dir_mode |= S_IXOTH; - - /* change folder */ - dir_mode |= DIRBITS; - if (dir_rx_set(dir_mode)) { - if (chmod( name, dir_mode ) < 0) - return -1; - } - param.st = st; - param.mode = file_mode; - if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, ¶m, 0, v_umask) < 0) - return -1; - - if (!dir_rx_set(dir_mode)) { - if (chmod( name, dir_mode ) < 0) - return -1; - } - return 0; } -static int RF_setfilmode_ads(VFS_FUNC_ARGS_SETFILEMODE) +/* ---------------- */ +static int RF_renamedir_ea(VFS_FUNC_ARGS_RENAMEDIR) { - return ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_HF )), mode, st, vol->v_umask); + return 0; } -/* ------------------- */ -static int RF_setdirunixmode_ads(VFS_FUNC_ARGS_SETDIRUNIXMODE) +/* ---------------- */ +static int RF_deletecurdir_ea(VFS_FUNC_ARGS_DELETECURDIR) { - char *adouble = vol->ad_path(name, ADFLAGS_DIR ); - char ad_p[ MAXPATHLEN + 1]; - int dropbox = vol->v_flags; - - strlcpy(ad_p,ad_dir(adouble), MAXPATHLEN + 1); - - if (dir_rx_set(mode)) { - - /* .AppleDouble */ - if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox, vol->v_umask) < 0) - return -1; - - /* .AppleDouble/.Parent */ - if (stickydirmode(ad_p, DIRBITS | mode, dropbox, vol->v_umask) < 0) - return -1; - } - - if (ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_DIR)), mode, st, vol->v_umask) < 0) - return -1; - - if (!dir_rx_set(mode)) { - if (stickydirmode(ad_p, DIRBITS | mode, dropbox, vol->v_umask) < 0) - return -1 ; - if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox, vol->v_umask) < 0) - return -1; - } return 0; } -/* ------------------- */ -struct dir_mode { - mode_t mode; - int dropbox; -}; - -static int setdirmode_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask) +/* ---------------- */ +static int RF_setdirunixmode_ea(VFS_FUNC_ARGS_SETDIRUNIXMODE) { - - struct dir_mode *param = data; - int ret = 0; /* 0 ignore error, -1 */ - - if (dir_rx_set(param->mode)) { - if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) { - if (flag) { - return 0; - } - return ret; - } - } - if (ads_setfilmode(name, param->mode, NULL, v_umask) < 0) - return ret; - - if (!dir_rx_set(param->mode)) { - if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) { - if (flag) { - return 0; - } - return ret; - } - } return 0; } -static int RF_setdirmode_ads(VFS_FUNC_ARGS_SETDIRMODE) +static int RF_setfilmode_ea(VFS_FUNC_ARGS_SETFILEMODE) { - char *adouble = vol->ad_path(name, ADFLAGS_DIR ); - char ad_p[ MAXPATHLEN + 1]; - struct dir_mode param; - - param.mode = mode; - param.dropbox = vol->v_flags; - - strlcpy(ad_p,ad_dir(adouble), sizeof(ad_p)); - - if (dir_rx_set(mode)) { - /* .AppleDouble */ - if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox, vol->v_umask) < 0) - return -1; - } - - if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, ¶m, vol_noadouble(vol), vol->v_umask)) - return -1; - - if (!dir_rx_set(mode)) { - if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox, vol->v_umask) < 0 ) - return -1; - } return 0; } -/* ------------------- */ -static int setdirowner_ads1_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_) +/* ---------------- */ +static int RF_setdirmode_ea(VFS_FUNC_ARGS_SETDIRMODE) { - struct perm *owner = data; - - if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) { - LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", - owner->uid, owner->gid, fullpathname(name), strerror(errno) ); - /* return ( -1 ); Sometimes this is okay */ - } return 0; } -static int setdirowner_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask _U_) +/* ---------------- */ +static int RF_setdirowner_ea(VFS_FUNC_ARGS_SETDIROWNER) { - struct perm *owner = data; - - if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag, 0) < 0) - return -1; - - if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) { - LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", - owner->uid, owner->gid, fullpathname(name), strerror(errno) ); - /* return ( -1 ); Sometimes this is okay */ - } - return 0; + return 0; } -static int RF_setdirowner_ads(VFS_FUNC_ARGS_SETDIROWNER) +static int RF_deletefile_ea(VFS_FUNC_ARGS_DELETEFILE) { - int noadouble = vol_noadouble(vol); - char adouble_p[ MAXPATHLEN + 1]; - struct stat st; - struct perm owner; - - owner.uid = uid; - owner.gid = gid; - - strlcpy(adouble_p, ad_dir(vol->ad_path(name, ADFLAGS_DIR )), sizeof(adouble_p)); - - if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble, 0)) - return -1; - - /* - * We cheat: we know that chown doesn't do anything. - */ - if ( stat( ".AppleDouble", &st ) < 0) { - if (errno == ENOENT && noadouble) - return 0; - LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) ); - return -1; - } - if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) { - LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", - uid, gid,fullpathname(".AppleDouble"), strerror(errno) ); - /* return ( -1 ); Sometimes this is okay */ - } return 0; } - -/* ------------------- */ -static int RF_deletefile_ads(VFS_FUNC_ARGS_DELETEFILE) +static int RF_copyfile_ea(VFS_FUNC_ARGS_COPYFILE) { - int ret = 0; - int cwd = -1; - char *ad_p; - - ad_p = ad_dir(vol->ad_path(file, ADFLAGS_HF )); - - if (dirfd != -1) { - if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) { - ret = AFPERR_MISC; - goto exit; - } - } - - ret = ads_delete_rf(ad_p); - - if (dirfd != -1 && fchdir(cwd) != 0) { - LOG(log_error, logtype_afpd, "RF_deletefile_ads: cant chdir back. exit!"); - exit(EXITERR_SYS); - } - -exit: - if (cwd != -1) - close(cwd); - - return ret; + return 0; } -/* --------------------------- */ -static int RF_renamefile_ads(VFS_FUNC_ARGS_RENAMEFILE) +/* ---------------- */ +static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE) { - char adsrc[ MAXPATHLEN + 1]; - int err = 0; - - strcpy( adsrc, ad_dir(vol->ad_path(src, 0 ))); - if (unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) < 0) { - struct stat st; - - err = errno; - if (errno == ENOENT) { - struct adouble ad; - - if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */ - return 0; - - /* 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. - */ - ad_init(&ad, vol->v_adouble, vol->v_ad_options); - if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) { - ad_close(&ad, ADFLAGS_HF); - - /* We must delete it */ - RF_deletefile_ads(vol, -1, dst ); - if (!unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) ) - err = 0; - else - err = errno; - } - else { /* it's something else, bail out */ - err = errno; - } - } - } - if (err) { - errno = err; - return -1; - } - return 0; + return 0; } +#if 0 /************************************************************************* * osx adouble format ************************************************************************/ @@ -915,6 +618,7 @@ static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE) } return 0; } +#endif /******************************************************************************************** * VFS chaining @@ -1003,10 +707,10 @@ static struct vfs_ops vfs_master_funcs = { }; /* - * Primary adouble modules: default, osx, sfm + * Primary adouble modules: v2, ea */ -static struct vfs_ops netatalk_adouble = { +static struct vfs_ops netatalk_adouble_v2 = { /* vfs_validupath: */ validupath_adouble, /* vfs_chown: */ RF_chown_adouble, /* vfs_renamedir: */ RF_renamedir_adouble, @@ -1021,34 +725,18 @@ static struct vfs_ops netatalk_adouble = { NULL }; -static struct vfs_ops netatalk_adouble_osx = { - /* vfs_validupath: */ validupath_osx, - /* vfs_chown: */ RF_chown_adouble, - /* vfs_renamedir: */ RF_renamedir_osx, - /* vfs_deletecurdir: */ RF_deletecurdir_osx, - /* vfs_setfilmode: */ RF_setfilmode_adouble, - /* vfs_setdirmode: */ RF_setdirmode_osx, - /* vfs_setdirunixmode:*/ RF_setdirunixmode_osx, - /* vfs_setdirowner: */ RF_setdirowner_osx, - /* vfs_deletefile: */ RF_deletefile_adouble, - /* vfs_renamefile: */ RF_renamefile_osx, - /* vfs_copyfile: */ NULL, - NULL -}; - -/* samba sfm format. ad_path shouldn't be set her */ -static struct vfs_ops netatalk_adouble_sfm = { - /* vfs_validupath: */ validupath_adouble, - /* vfs_chown: */ RF_chown_ads, - /* vfs_renamedir: */ RF_renamedir_adouble, - /* vfs_deletecurdir: */ RF_deletecurdir_ads, - /* vfs_setfilmode: */ RF_setfilmode_ads, - /* vfs_setdirmode: */ RF_setdirmode_ads, - /* vfs_setdirunixmode:*/ RF_setdirunixmode_ads, - /* vfs_setdirowner: */ RF_setdirowner_ads, - /* vfs_deletefile: */ RF_deletefile_ads, - /* vfs_renamefile: */ RF_renamefile_ads, - /* vfs_copyfile: */ NULL, +static struct vfs_ops netatalk_adouble_ea = { + /* vfs_validupath: */ validupath_ea, + /* vfs_chown: */ RF_chown_ea, + /* vfs_renamedir: */ RF_renamedir_ea, + /* vfs_deletecurdir: */ RF_deletecurdir_ea, + /* vfs_setfilmode: */ RF_setfilmode_ea, + /* vfs_setdirmode: */ RF_setdirmode_ea, + /* vfs_setdirunixmode:*/ RF_setdirunixmode_ea, + /* vfs_setdirowner: */ RF_setdirowner_ea, + /* vfs_deletefile: */ RF_deletefile_ea, + /* vfs_renamefile: */ RF_renamefile_ea, + /* vfs_copyfile: */ RF_copyfile_ea, NULL }; @@ -1150,17 +838,12 @@ void initvol_vfs(struct vol *vol) vol->vfs = &vfs_master_funcs; /* Default adouble stuff */ - if (vol->v_adouble == AD_VERSION2_OSX) { - vol->vfs_modules[0] = &netatalk_adouble_osx; - vol->ad_path = ad_path_osx; - } - else if (vol->v_adouble == AD_VERSION1_SFM) { - vol->vfs_modules[0] = &netatalk_adouble_sfm; - vol->ad_path = ad_path_sfm; - } - else { - vol->vfs_modules[0] = &netatalk_adouble; + if (vol->v_adouble == AD_VERSION2) { + vol->vfs_modules[0] = &netatalk_adouble_v2; vol->ad_path = ad_path; + } else { + vol->vfs_modules[0] = &netatalk_adouble_ea; + vol->ad_path = ad_path_ea; } /* Extended Attributes */ -- 2.39.2