sd.sd_last += len + 1;
s_path.m_name = NULL;
+
+ /* Convert adouble:v2 to adouble:ea on the fly */
+ (void)ad_convert(s_path.u_name, &s_path.st, vol);
+
/*
* If a fil/dir is not a dir, it's a file. This is slightly
* inaccurate, since that means /dev/null is a file, /dev/printer
if ( actcnt == 0 ) {
sd.sd_did = 0; /* invalidate sd struct to force re-read */
+ /*
+ * in case were converting adouble stuff:
+ * after enumerating the whole dir we should have converted everything
+ * thus the .AppleDouble dir shouls be empty thus we can no try to
+ * delete it
+ */
+ if (vol->v_adouble == AD_VERSION_EA && ! (vol->v_flags & AFPVOL_NOV2TOEACONV))
+ (void)rmdir(".AppleDouble");
+
return( AFPERR_NOOBJ );
}
sd.sd_sindex = sindex + actcnt;
return( retvalue );
}
-/* ----------------------- */
-static int copy_all(const int dfd, const void *buf,
- size_t buflen)
-{
- ssize_t cc;
-
-#ifdef DEBUG
- LOG(log_debug9, logtype_afpd, "begin copy_all:");
-#endif /* DEBUG */
-
- while (buflen > 0) {
- if ((cc = write(dfd, buf, buflen)) < 0) {
- switch (errno) {
- case EINTR:
- continue;
- default:
- return -1;
- }
- }
- buflen -= cc;
- }
-
-#ifdef DEBUG
- LOG(log_debug9, logtype_afpd, "end copy_all:");
-#endif /* DEBUG */
-
- return 0;
-}
-
-/* --------------------------
- * 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;
- size_t size;
- struct stat st;
- #define BUF 128*1024*1024
-
- if (fstat(sfd, &st) == 0) {
-
- while (1) {
- if ( offset >= st.st_size) {
- return 0;
- }
- size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
- if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
- switch (errno) {
- case ENOSYS:
- case EINVAL: /* there's no guarantee that all fs support sendfile */
- goto no_sendfile;
- default:
- return -1;
- }
- }
- }
- }
- no_sendfile:
- lseek(sfd, offset, SEEK_SET);
-#endif
-
- while (1) {
- if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
- if (errno == EINTR)
- continue;
- err = -1;
- break;
- }
-
- if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
- break;
- }
- }
- return err;
-}
-
/* ----------------------------------
* if newname is NULL (from directory.c) we don't want to copy the resource fork.
* because we are doing it elsewhere.
options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS;
else if (strcasecmp(p, "noacls") == 0)
options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS;
+ else if (strcasecmp(p, "nov2toeaconv") == 0)
+ options[VOLOPT_FLAGS].i_value |= AFPVOL_NOV2TOEACONV;
p = strtok(NULL, ",");
}
* For MacOS8.x support we need to create the
* .Parent file here if it doesn't exist. */
+ /* Convert adouble:v2 to adouble:ea on the fly */
+ (void)ad_convert(vol->v_path, st, vol);
+
ad_init(&ad, vol);
if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) {
isad = 0;
const char *(*ad_path)(const char *, int);
int (*ad_mkrf)(const char *);
int (*ad_rebuild_header)(struct adouble *);
- int (*ad_header_read)(const char *, struct adouble *, struct stat *);
+ int (*ad_header_read)(const char *, struct adouble *, const struct stat *);
int (*ad_header_upgrade)(struct adouble *, const char *);
};
extern int ad_stat (const char *, struct stat *);
extern int ad_metadata (const char *, int, struct adouble *);
extern int ad_metadataat (int, const char *, int, struct adouble *);
-
-/* 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),
- */
-static inline mode_t ad_hf_mode (mode_t mode)
-{
- mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
- /* fnctl lock need write access */
- if ((mode & S_IRUSR))
- mode |= S_IWUSR;
- if ((mode & S_IRGRP))
- mode |= S_IWGRP;
- if ((mode & S_IROTH))
- mode |= S_IWOTH;
-
- /* if write mode set add read mode */
- if ((mode & S_IWUSR))
- mode |= S_IRUSR;
- if ((mode & S_IWGRP))
- mode |= S_IRGRP;
- if ((mode & S_IWOTH))
- mode |= S_IROTH;
-
- return mode;
-}
+extern mode_t ad_hf_mode(mode_t mode);
+extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol);
/* ad_read.c/ad_write.c */
extern int sys_ftruncate(int fd, off_t length);
extern ssize_t adf_pwrite(struct ad_fd *, const void *, size_t, off_t);
extern int ad_dtruncate(struct adouble *, off_t);
extern int ad_rtruncate(struct adouble *, off_t);
+extern int copy_fork(int eid, struct adouble *add, struct adouble *ads);
/* ad_size.c */
extern off_t ad_size (const struct adouble *, uint32_t );
/* flags for AFS and quota 0xxx0 */
#define AFPVOL_GVSMASK (7<<2)
-#define AFPVOL_NONE (0<<2)
+#define AFPVOL_NONE (0<<2)
#define AFPVOL_AFSGVS (1<<2)
-#define AFPVOL_USTATFS (2<<2)
-#define AFPVOL_UQUOTA (4<<2)
+#define AFPVOL_USTATFS (1<<3)
+#define AFPVOL_UQUOTA (1<<4)
/*
Flags that alter volume behaviour.
Keep in sync with libatalk/util/volinfo.c
*/
+#define AFPVOL_NOV2TOEACONV (1 << 5) /* no adouble:v2 to adouble:ea conversion */
#define AFPVOL_RO (1 << 8) /* read-only volume */
#define AFPVOL_NOHEX (1 << 10) /* don't do :hex translation */
#define AFPVOL_USEDOTS (1 << 11) /* use real dots */
uint32_t len;
for ( eid = 0; eid < ADEID_MAX; eid++ ) {
- if ( ads->ad_eid[ eid ].ade_off == 0 ) {
+ if ( ads->ad_eid[ eid ].ade_off == 0 || add->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) {
+ if (!len || len != add->ad_eid[ eid ].ade_len)
continue;
- }
- if (eid != ADEID_COMMENT && add->ad_eid[ eid ].ade_len != len ) {
+ switch (eid) {
+ case ADEID_COMMENT:
+ case ADEID_PRIVDEV:
+ case ADEID_PRIVINO:
+ case ADEID_PRIVSYN:
+ case ADEID_PRIVID:
continue;
+ default:
+ ad_setentrylen( add, eid, len );
+ memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len );
}
-
- ad_setentrylen( add, eid, len );
- memcpy( ad_entry( add, eid ), ad_entry( ads, eid ), len );
}
add->ad_rlen = ads->ad_rlen;
return 0;
#include <atalk/logger.h>
#include <atalk/adouble.h>
#include <atalk/util.h>
+#include <atalk/unix.h>
#include <atalk/ea.h>
#include <atalk/bstrlib.h>
#include <atalk/bstradd.h>
/* Forward declarations */
static int ad_mkrf(const char *path);
-static int ad_header_read(const char *path, struct adouble *ad, struct stat *hst);
+static int ad_header_read(const char *path, struct adouble *ad, const struct stat *hst);
static int ad_header_upgrade(struct adouble *ad, const char *name);
static int ad_mkrf_ea(const char *path);
-static int ad_header_read_ea(const char *path, struct adouble *ad, struct stat *hst);
+static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst);
static int ad_header_upgrade_ea(struct adouble *ad, const char *name);
static int ad_reso_size(const char *path, int adflags, struct adouble *ad);
static int ad_mkrf_osx(const char *path);
* NOTE: we're assuming that the resource fork is kept at the end of
* the file. also, mmapping won't work for the hfs fs until it
* understands how to mmap header files. */
-static int ad_header_read(const char *path _U_, struct adouble *ad, struct stat *hst)
+static int ad_header_read(const char *path _U_, struct adouble *ad, const struct stat *hst)
{
char *buf = ad->ad_data;
uint16_t nentries;
}
/* Read an ._ file, only uses the resofork, finderinfo is taken from EA */
-static int ad_header_read_osx(const char *path _U_, struct adouble *ad, struct stat *hst)
+static int ad_header_read_osx(const char *path _U_, struct adouble *ad, const struct stat *hst)
{
EC_INIT;
struct adouble adosx;
EC_EXIT;
}
-static int ad_header_read_ea(const char *path, struct adouble *ad, struct stat *hst _U_)
+static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst _U_)
{
uint16_t nentries;
int len;
return oflags;
}
-static int ad_conv_v22ea(const char *path, int adflags, const struct adouble *adea)
+static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
{
EC_INIT;
struct adouble adv2;
- const char *adp;
+ struct adouble adea;
+ const char *adpath;
+ int adflags;
- LOG(log_note, logtype_default,"ad_conv_v22ea(\"%s\"): BEGIN", fullpathname(path));
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));
- ad_init_old(&adv2, AD_VERSION2, adea->ad_options);
- EC_NULL( adp = adv2.ad_ops->ad_path(path, adflags) );
+ ad_init(&adea, vol);
+ ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+ adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
- LOG(log_note, logtype_default,"ad_conv_v22ea(\"%s\"): adouble:v2 path: \"%s\"",
- fullpathname(path), fullpathname(adp));
+ /* Open and lock adouble:v2 file */
+ EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );
+ EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+ EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );
+
+ /* Create a adouble:ea meta EA */
+ EC_ZERO_LOG( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE) );
+ EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
+ ad_flush(&adea);
EC_CLEANUP:
+ EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
+ EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
EC_EXIT;
}
+static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struct vol *vol)
+{
+ EC_INIT;
+ struct adouble adv2;
+ struct adouble adea;
+
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): BEGIN", fullpathname(path));
+
+ if (S_ISDIR(sp->st_mode))
+ return 0;
+
+ ad_init(&adea, vol);
+ ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+
+ /* Open and lock adouble:v2 file */
+ EC_ZERO( ad_open(&adv2, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR) );
+ if (adv2.ad_rlen > 0) {
+ EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+
+ /* Create a adouble:ea resource fork */
+ EC_ZERO_LOG( ad_open(&adea, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) );
+
+ EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
+ adea.ad_rlen = adv2.ad_rlen;
+ ad_flush(&adea);
+ }
+
+EC_CLEANUP:
+ EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_RF) );
+ EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_RF) );
+ EC_EXIT;
+}
static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble *ad)
{
return ret;
}
+
+int ad_convert(const char *path, const struct stat *sp, const struct vol *vol)
+{
+ EC_INIT;
+ const char *adpath;
+ int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+
+ if (!(vol->v_adouble == AD_VERSION_EA) || (vol->v_flags & AFPVOL_NOV2TOEACONV))
+ goto EC_CLEANUP;
+
+ EC_ZERO( ad_conv_v22ea_hf(path, sp, vol) );
+ EC_ZERO( ad_conv_v22ea_rf(path, sp, vol) );
+
+ EC_NULL( adpath = ad_path(path, adflags) );
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): deleting adouble:v2 file: \"%s\"",
+ path, fullpathname(adpath));
+
+ become_root();
+ EC_ZERO_LOG( unlink(adpath) );
+ unbecome_root();
+
+EC_CLEANUP:
+ EC_EXIT;
+}
+
+/* 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),
+ */
+mode_t ad_hf_mode(mode_t mode)
+{
+ mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+ /* fnctl lock need write access */
+ if ((mode & S_IRUSR))
+ mode |= S_IWUSR;
+ if ((mode & S_IRGRP))
+ mode |= S_IWGRP;
+ if ((mode & S_IROTH))
+ mode |= S_IWOTH;
+
+ /* if write mode set add read mode */
+ if ((mode & S_IWUSR))
+ mode |= S_IRUSR;
+ if ((mode & S_IWGRP))
+ mode |= S_IRGRP;
+ if ((mode & S_IWOTH))
+ mode |= S_IROTH;
+
+ return mode;
+}
return 0;
}
+
+/* ----------------------- */
+static int copy_all(const int dfd, const void *buf,
+ size_t buflen)
+{
+ ssize_t cc;
+
+ while (buflen > 0) {
+ if ((cc = write(dfd, buf, buflen)) < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ default:
+ return -1;
+ }
+ }
+ buflen -= cc;
+ }
+
+ return 0;
+}
+
+/* --------------------------
+ * copy only the fork data stream
+*/
+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;
+ size_t size;
+ struct stat st;
+ #define BUF 128*1024*1024
+
+ if (fstat(sfd, &st) == 0) {
+
+ while (1) {
+ if ( offset >= st.st_size) {
+ return 0;
+ }
+ size = (st.st_size -offset > BUF)?BUF:st.st_size -offset;
+ if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) {
+ switch (errno) {
+ case ENOSYS:
+ case EINVAL: /* there's no guarantee that all fs support sendfile */
+ goto no_sendfile;
+ default:
+ return -1;
+ }
+ }
+ }
+ }
+ no_sendfile:
+ lseek(sfd, offset, SEEK_SET);
+#endif
+
+ while (1) {
+ if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
+ if (errno == EINTR)
+ continue;
+ err = -1;
+ break;
+ }
+
+ if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
+ break;
+ }
+ }
+ return err;
+}