#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>
/* 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_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)
-#define ADEDOFF_PRIVID_EA (ADEDOFF_AFPFILEI_EA + ADEDLEN_AFPFILEI)
+#define ADEDOFF_PRIVDEV_EA (ADEDOFF_AFPFILEI_EA + ADEDLEN_AFPFILEI)
+#define ADEDOFF_PRIVINO_EA (ADEDOFF_PRIVDEV_EA + ADEDLEN_PRIVDEV)
+#define ADEDOFF_PRIVSYN_EA (ADEDOFF_PRIVINO_EA + ADEDLEN_PRIVINO)
+#define ADEDOFF_PRIVID_EA (ADEDOFF_PRIVSYN_EA + ADEDLEN_PRIVSYN)
/* 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 */
/* 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);
static struct adouble_fops ad_adouble = {
&ad_path,
&ad_mkrf,
- &ad_rebuild_adouble_header,
+ &ad_rebuild_adouble_header_v2,
&ad_header_read,
&ad_header_upgrade,
};
&ad_path_osx,
&ad_mkrf_osx,
#endif
- &ad_rebuild_adouble_header,
+ &ad_rebuild_adouble_header_ea,
&ad_header_read_ea,
&ad_header_upgrade_ea,
};
-static struct adouble_fops ad_osx = {
- &ad_path_osx,
- &ad_mkrf_osx,
- &ad_rebuild_adouble_header,
- &ad_header_read,
- &ad_header_upgrade,
-};
-
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_COMMENT, ADEDOFF_COMMENT_EA, ADEDLEN_INIT},
{ADEID_FILEDATESI, ADEDOFF_FILEDATESI_EA, ADEDLEN_FILEDATESI},
{ADEID_AFPFILEI, ADEDOFF_AFPFILEI_EA, ADEDLEN_AFPFILEI},
+ {ADEID_PRIVDEV, ADEDOFF_PRIVDEV_EA, ADEDLEN_INIT},
+ {ADEID_PRIVINO, ADEDOFF_PRIVINO_EA, ADEDLEN_INIT},
+ {ADEID_PRIVSYN, ADEDOFF_PRIVSYN_EA, ADEDLEN_INIT},
{ADEID_PRIVID, ADEDOFF_PRIVID_EA, ADEDLEN_INIT},
{0, 0, 0}
};
* 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;
struct stat st;
/* read the header */
- if ((header_len = adf_pread( ad->ad_mdp, buf, AD_DATASZ, 0)) < 0) {
+ if ((header_len = adf_pread( ad->ad_mdp, buf, AD_DATASZ2, 0)) < 0) {
return -1;
}
if (header_len < AD_HEADER_LEN) {
return 0;
}
+/* error here means it's not ad ._ adouble:osx file and thus we return 1 */
+int ad_valid_header_osx(const char *path)
+{
+ EC_INIT;
+ int fd = -1;
+ struct adouble adosx;
+ char *buf = &adosx.ad_data[0];
+ ssize_t header_len;
+
+ LOG(log_debug, logtype_afpd, "ad_valid_header_osx(\"%s\"): BEGIN", fullpathname(path));
+
+ EC_NEG1( fd = open(path, O_RDONLY) );
+
+ /* read the header */
+ EC_NEG1( header_len = read(fd, buf, AD_DATASZ_OSX) );
+
+ if (header_len < AD_HEADER_LEN)
+ EC_FAIL;
+
+ memcpy(&adosx.ad_magic, buf, sizeof(adosx.ad_magic));
+ memcpy(&adosx.ad_version, buf + ADEDOFF_VERSION, sizeof(adosx.ad_version));
+ adosx.ad_magic = ntohl(adosx.ad_magic);
+ adosx.ad_version = ntohl(adosx.ad_version);
+
+ if ((adosx.ad_magic != AD_MAGIC) || (adosx.ad_version != AD_VERSION2)) {
+ LOG(log_error, logtype_afpd, "ad_valid_header_osx: not an adouble:ox file");
+ EC_FAIL;
+ }
+
+EC_CLEANUP:
+ LOG(log_debug, logtype_afpd, "ad_valid_header_osx(\"%s\"): END: %d", fullpathname(path), ret);
+ if (fd != -1)
+ close(fd);
+ if (ret != 0)
+ return 1;
+ return 0;
+}
+
/* 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;
if (adflags & ADFLAGS_RDWR)
oflags |= O_RDWR;
if (adflags & ADFLAGS_RDONLY) {
- if (((adfile & ADFLAGS_DF) && (adflags & ADFLAGS_SETSHRMD))
+ if (((adfile == ADFLAGS_DF || adfile == ADFLAGS_RF) && (adflags & ADFLAGS_SETSHRMD))
/* need rw access for locks */
- || ((ad->ad_vers == AD_VERSION2) && (adflags & ADFLAGS_HF)))
+ || ((adfile == ADFLAGS_HF) && (ad->ad_vers == AD_VERSION2)))
/* need rw access for adouble file for the case:
- 1) openfork(data:O_RDONLY), 2) openfork(reso:O_RDWR) */
+ 1) openfork(data+meta:O_RDONLY), 2) openfork(reso(=meta):O_RDWR) */
oflags |= O_RDWR;
else
oflags |= O_RDONLY;
EC_FAIL;
}
ad->ad_data_fork.adf_syml[lsz] = 0;
- ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
+ ad->ad_data_fork.adf_fd = AD_SYMLINK;
break;
default:
EC_FAIL;
oflags = O_NOFOLLOW | (ad2openflags(ad, ADFLAGS_DF, adflags) & ~(O_CREAT | O_TRUNC));
- if (ad_meta_fileno(ad) == -2)
+ if (ad_meta_fileno(ad) == AD_SYMLINK)
/* symlink */
EC_EXIT;
LOG(log_debug, logtype_default, "ad_open_hf_ea(\"%s\"): created metadata EA", path);
}
- ad->ad_mdp->adf_refcount++;
+ if (ad_meta_fileno(ad) != -1)
+ ad->ad_mdp->adf_refcount++;
(void)ad_reso_size(path, adflags, ad);
EC_CLEANUP:
EC_EXIT;
}
-/*!
- * Open ressource fork
- *
- * Only for adouble:ea, a nullop otherwise because adouble:v2 has the ressource fork as part
- * of the adouble file which is openend by ADFLAGS_HF.
- */
-static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *ad)
+static int ad_open_rf_v2(const char *path, int adflags, int mode, struct adouble *ad)
+{
+ /*
+ * ad_open_hf_v2() does the work, but if it failed and adflags are ADFLAGS_NOHF | ADFLAGS_RF
+ * ad_open_hf_v2() didn't give an error, but we're supposed to return a reso fork fd
+ */
+ if (!AD_RSRC_OPEN(ad) && !(adflags & ADFLAGS_NORF))
+ return -1;
+ return 0;
+}
+
+static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble *ad)
{
EC_INIT;
int oflags;
struct stat st;
#endif
- if (ad->ad_vers != AD_VERSION_EA)
- return 0;
-
LOG(log_debug, logtype_default, "ad_open_rf(\"%s\"): BEGIN", fullpathname(path));
- oflags = O_NOFOLLOW | (ad2openflags(ad, ADFLAGS_HF, adflags) & ~O_CREAT);
+ oflags = O_NOFOLLOW | (ad2openflags(ad, ADFLAGS_RF, adflags) & ~O_CREAT);
if (ad_reso_fileno(ad) != -1) {
/* the file is already open, but we want write access: */
goto EC_CLEANUP;
}
#ifdef HAVE_EAFD
- if (ad_meta_fileno(ad) == -1)
+ if (ad_meta_fileno(ad) < 0)
EC_FAIL;
if ((ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), AD_EA_RESO, oflags)) == -1) {
if (!(adflags & ADFLAGS_CREATE)) {
EC_EXIT;
}
+/*!
+ * Open ressource fork
+ */
+static int ad_open_rf(const char *path, int adflags, int mode, struct adouble *ad)
+{
+ int ret = 0;
+
+ switch (ad->ad_vers) {
+ case AD_VERSION2:
+ ret = ad_open_rf_v2(path, adflags, mode, ad);
+ break;
+ case AD_VERSION_EA:
+ ret = ad_open_rf_ea(path, adflags, mode, ad);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
/***********************************************************************************
* API functions
********************************************************************************* */
/* Checking for open forks requires sharemode lock support (ie RDWR instead of RDONLY) */
adflags |= ADFLAGS_SETSHRMD;
+ if (adflags & ADFLAGS_SETSHRMD)
+ /* sharemode locks are stored in the data fork */
+ adflags |= ADFLAGS_DF;
+
if (ad->ad_vers == AD_VERSION2) {
- if (adflags & ADFLAGS_SETSHRMD)
- /* sharemode locks are stored in the data fork, adouble:v2 needs this extra handling here */
- adflags |= ADFLAGS_DF;
if (adflags & ADFLAGS_RF)
adflags |= ADFLAGS_HF;
if (adflags & ADFLAGS_NORF)
return ret;
}
+
+/* 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;
+}