+/* 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_ad, "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_warning, logtype_ad, "ad_valid_header_osx(\"%s\"): not an adouble:osx file", fullpathname(path));
+ EC_FAIL;
+ }
+
+ if (strncmp(buf + ADEDOFF_FILLER, "Mac OS X", strlen("Mac OS X")) == 0)
+ /*
+ * It's a split fork created by OS X, it's not our "own" ._ file
+ * and thus not a valid header in this context.
+ * We allow enumeration and access.
+ */
+ EC_FAIL;
+
+EC_CLEANUP:
+ LOG(log_debug, logtype_ad, "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, const struct stat *hst)
+{
+ EC_INIT;
+ struct adouble adosx;
+ char *buf = &adosx.ad_data[0];
+ uint16_t nentries;
+ int len;
+ ssize_t header_len;
+ struct stat st;
+
+ memset(buf, 0, sizeof(adosx.ad_data));
+
+ /* read the header */
+ EC_NEG1( header_len = adf_pread(ad->ad_rfp, buf, AD_DATASZ_OSX, 0) );
+
+ if (header_len < AD_HEADER_LEN) {
+ errno = EIO;
+ return -1;
+ }
+
+ 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_ad, "ad_header_read_osx: can't parse AppleDouble header");
+ errno = EIO;
+ return -1;
+ }
+
+ memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
+ nentries = ntohs(nentries);
+ len = nentries * AD_ENTRY_LEN;
+
+ if (len + AD_HEADER_LEN > sizeof(adosx.ad_data))
+ len = sizeof(adosx.ad_data) - AD_HEADER_LEN;
+
+ buf += AD_HEADER_LEN;
+ if (len > header_len - AD_HEADER_LEN) {
+ LOG(log_error, logtype_ad, "ad_header_read_osx: can't read entry info.");
+ errno = EIO;
+ return -1;
+ }
+
+ nentries = len / AD_ENTRY_LEN;
+ parse_entries(&adosx, buf, nentries);
+
+ if (ad_getentryoff(&adosx, ADEID_RFORK) == 0
+ || ad_getentryoff(&adosx, ADEID_RFORK) > sizeof(ad->ad_data)
+ || ad_getentryoff(&adosx, ADEID_RFORK) > header_len
+ ) {
+ LOG(log_error, logtype_ad, "ad_header_read_osx: problem with rfork entry offset.");
+ errno = EIO;
+ return -1;
+ }
+
+ if (hst == NULL) {
+ hst = &st;
+ EC_NEG1( fstat(ad_reso_fileno(ad), &st) );
+ }
+
+ ad_setentryoff(ad, ADEID_RFORK, ad_getentryoff(&adosx, ADEID_RFORK));
+ ad->ad_rlen = hst->st_size - ad_getentryoff(ad, ADEID_RFORK);
+
+EC_CLEANUP:
+ EC_EXIT;
+}
+
+static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst _U_)