+/* 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;
+
+ if (!(ad->ad_hf.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_hf.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) {
+ 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++;
+ }