+ 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++;
+ }
+
+ memset(ad->ad_data + AD_HEADER_LEN, 0, AD_DATASZ - AD_HEADER_LEN);
+
+ /* copy the saved entries to the new header */
+ eid = entry_order2;
+ while (eid->id) {
+ if ( eid->id > 2 && entry_len[eid->id] > 0) {
+ memcpy(ad->ad_data+eid->offset, databuf[eid->id], entry_len[eid->id]);
+ }
+ ad->ad_eid[eid->id].ade_off = eid->offset;
+ ad->ad_eid[eid->id].ade_len = entry_len[eid->id];
+ eid++;
+ }
+
+ /* rebuild the header and cleanup */
+ LOG(log_debug, logtype_default, "updated AD2 header %s", path);
+ ad_flush(ad, ADFLAGS_HF );
+ ret = 0;
+
+bail_lock:
+ ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
+bail_err:
+ return ret;
+}
+
+/* ------------------------------------------
+ FIXME work only if < 2GB
+*/
+static int ad_convert(struct adouble *ad, const char *path)