return 0;
}
-/* ----------------------------------- */
-static int new_ad_header(struct adouble *ad, const char *path, struct stat *stp, int adflags)
+
+/**
+ * Initialize offset pointers
+ */
+int ad_init_offsets(struct adouble *ad)
{
const struct entry *eid;
- uint16_t ashort;
- struct stat st;
-
- LOG(log_debug, logtype_ad, "new_ad_header(\"%s\")", path);
- if (ad->ad_magic == AD_MAGIC) {
- LOG(log_debug, logtype_ad, "new_ad_header(\"%s\"): already initialized", path);
+ if (ad->ad_magic == AD_MAGIC)
return 0;
- }
ad->ad_magic = AD_MAGIC;
ad->ad_version = ad->ad_vers & 0x0f0000;
eid++;
}
- /* put something sane in the directory finderinfo */
- if (stp == NULL) {
- stp = &st;
- if (lstat(path, &st) != 0)
- return -1;
- }
+ return 0;
+}
- if ((adflags & ADFLAGS_DIR)) {
- /* set default view */
- ashort = htons(FINDERINFO_CLOSEDVIEW);
- memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
- } else {
- /* set default creator/type fields */
- memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
- memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
- }
+/* ----------------------------------- */
+static int new_ad_header(struct adouble *ad, const char *path, struct stat *stp, int adflags)
+{
+ const struct entry *eid;
+ uint16_t ashort;
+ struct stat st;
+
+ LOG(log_debug, logtype_ad, "new_ad_header(\"%s\")", path);
+
+ if (ad_init_offsets(ad) != 0)
+ return -1;
+
+ /* set default creator/type fields */
+ memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
+ memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
/* make things invisible */
if ((ad->ad_options & ADVOL_INVDOTS)
}
/* put something sane in the date fields */
+ if (stp == NULL) {
+ stp = &st;
+ if (lstat(path, &st) != 0)
+ return -1;
+ }
ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, stp->st_mtime);
ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, stp->st_mtime);
ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, stp->st_mtime);
static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst _U_)
{
+ EC_INIT;
uint16_t nentries;
int len;
ssize_t header_len;
if (ad_meta_fileno(ad) != -1)
header_len = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA);
else
- header_len = sys_lgetxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA);
- if (header_len < 1) {
+ header_len = sys_getxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA);
+ if (header_len < 1) {
LOG(log_debug, logtype_ad, "ad_header_read_ea: %s", strerror(errno));
- return -1;
+ EC_FAIL;
}
- if (header_len < AD_HEADER_LEN) {
- LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): bogus AppleDouble header.", fullpathname(path));
- errno = EIO;
- return -1;
+ if (header_len < AD_DATASZ_EA) {
+ LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): short metadata EA", fullpathname(path));
+ errno = EINVAL;
+ EC_FAIL;
}
memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic ));
if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) {
LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): wrong magic or version", fullpathname(path));
- errno = EIO;
- return -1;
+ errno = EINVAL;
+ EC_FAIL;
}
memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
nentries = ntohs( nentries );
-
- /* Protect against bogus nentries */
- len = nentries * AD_ENTRY_LEN;
- if (len + AD_HEADER_LEN > sizeof(ad->ad_data))
- len = sizeof(ad->ad_data) - AD_HEADER_LEN;
- if (len > header_len - AD_HEADER_LEN) {
- LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): can't read entry info.", fullpathname(path));
- errno = EIO;
- return -1;
+ if (nentries != ADEID_NUM_EA) {
+ LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): invalid number of entries: %d", fullpathname(path), nentries);
+ errno = EINVAL;
+ EC_FAIL;
}
- nentries = len / AD_ENTRY_LEN;
/* Now parse entries */
parse_entries(ad, buf + AD_HEADER_LEN, nentries);
- return 0;
+ if (nentries != ADEID_NUM_EA
+ || !ad_entry(ad, ADEID_FINDERI)
+ || !ad_entry(ad, ADEID_COMMENT)
+ || !ad_entry(ad, ADEID_FILEDATESI)
+ || !ad_entry(ad, ADEID_AFPFILEI)
+ || !ad_entry(ad, ADEID_PRIVDEV)
+ || !ad_entry(ad, ADEID_PRIVINO)
+ || !ad_entry(ad, ADEID_PRIVSYN)
+ || !ad_entry(ad, ADEID_PRIVID)) {
+ LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): invalid metadata EA", fullpathname(path));
+ errno = EINVAL;
+ EC_FAIL;
+ }
+
+EC_CLEANUP:
+ if (ret != 0 && errno == EINVAL) {
+ become_root();
+ (void)sys_removexattr(path, AD_EA_META);
+ unbecome_root();
+ LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): deleted invalid metadata EA", fullpathname(path), nentries);
+ errno = ENOENT;
+ }
+ EC_EXIT;
}
/*!
{
int ret = 0;
- memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
+ ad->ad_meta_refcount++;
switch (ad->ad_vers) {
case AD_VERSION2:
break;
}
- if (ret == 0)
- ad->ad_meta_refcount++;
- else
+ if (ret != 0) {
+ ad->ad_meta_refcount--;
ret = ad_error(ad, adflags);
+ }
return ret;
}
EC_FAIL;
}
ad->ad_rfp->adf_flags &= ~( O_TRUNC | O_CREAT );
+ ad->ad_reso_refcount++;
ad->ad_rfp->adf_refcount++;
EC_NEG1_LOG( ad->ad_rlen = ad_reso_size(path, adflags, ad));
goto EC_CLEANUP;