2 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
3 * Copyright (c) 1990,1991 Regents of The University of Michigan.
6 * Permission to use, copy, modify, and distribute this software and
7 * its documentation for any purpose and without fee is hereby granted,
8 * provided that the above copyright notice appears in all copies and
9 * that both that copyright notice and this permission notice appear
10 * in supporting documentation, and that the name of The University
11 * of Michigan not be used in advertising or publicity pertaining to
12 * distribution of the software without specific, written prior
13 * permission. This software is supplied as is without expressed or
14 * implied warranties of any kind.
16 * Research Systems Unix Group
17 * The University of Michigan
19 * 535 W. William Street
22 * netatalk@itd.umich.edu
36 #include <sys/types.h>
38 #include <sys/param.h>
41 #include <netatalk/endian.h>
42 #include <atalk/adouble.h>
44 #include "ad_private.h"
47 #define MAX(a, b) ((a) < (b) ? (b) : (a))
51 * AppleDouble entry default offsets.
52 * The layout looks like this:
54 * this is the v1 layout:
56 * | NAME | COMMENT | FILEI | FINDERI | RFORK |
58 * we need to change it to look like this:
61 * field length (in bytes)
64 * FILEDATESI 16 replaces FILEI
68 * SHORTNAME 12 8.3 new
71 * so, all we need to do is replace FILEI with FILEDATESI, move RFORK,
72 * and add in the new fields.
74 * NOTE: the HFS module will need similar modifications to interact with
78 #define ADEDOFF_MAGIC (0)
79 #define ADEDOFF_VERSION (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
80 #define ADEDOFF_FILLER (ADEDOFF_VERSION + ADEDLEN_VERSION)
81 #define ADEDOFF_NENTRIES (ADEDOFF_FILLER + ADEDLEN_FILLER)
83 /* initial lengths of some of the fields */
84 #define ADEDLEN_INIT 0
86 #define ADEID_NUM_V1 5
87 #define ADEDOFF_NAME_V1 (AD_HEADER_LEN + ADEID_NUM_V1*AD_ENTRY_LEN)
88 #define ADEDOFF_COMMENT_V1 (ADEDOFF_NAME_V1 + ADEDLEN_NAME)
89 #define ADEDOFF_FILEI (ADEDOFF_COMMENT_V1 + ADEDLEN_COMMENT)
90 #define ADEDOFF_FINDERI_V1 (ADEDOFF_FILEI + ADEDLEN_FILEI)
91 #define ADEDOFF_RFORK_V1 (ADEDOFF_FINDERI_V1 + ADEDLEN_FINDERI)
93 /* i stick things in a slightly different order than their eid order in
94 * case i ever want to separate RootInfo behaviour from the rest of the
96 #define ADEID_NUM_V2 9
97 #define ADEDOFF_NAME_V2 (AD_HEADER_LEN + ADEID_NUM_V2*AD_ENTRY_LEN)
98 #define ADEDOFF_COMMENT_V2 (ADEDOFF_NAME_V2 + ADEDLEN_NAME)
99 #define ADEDOFF_FILEDATESI (ADEDOFF_COMMENT_V2 + ADEDLEN_COMMENT)
100 #define ADEDOFF_FINDERI_V2 (ADEDOFF_FILEDATESI + ADEDLEN_FILEDATESI)
101 #define ADEDOFF_DID (ADEDOFF_FINDERI_V2 + ADEDLEN_FINDERI)
102 #define ADEDOFF_AFPFILEI (ADEDOFF_DID + ADEDLEN_DID)
103 #define ADEDOFF_SHORTNAME (ADEDOFF_AFPFILEI + ADEDLEN_AFPFILEI)
104 #define ADEDOFF_PRODOSFILEI (ADEDOFF_SHORTNAME + ADEDLEN_SHORTNAME)
105 #define ADEDOFF_RFORK_V2 (ADEDOFF_PRODOSFILEI + ADEDLEN_PRODOSFILEI)
109 /* we keep local copies of a bunch of stuff so that we can initialize things
112 /* Bits in the finderinfo data.
113 * see etc/afpd/{directory.c,file.c} for the finderinfo structure
115 #define FINDERINFO_CUSTOMICON 0x4
116 #define FINDERINFO_CLOSEDVIEW 0x100
118 /* offsets in finderinfo */
119 #define FINDERINFO_FRTYPEOFF 0
120 #define FINDERINFO_FRCREATOFF 4
121 #define FINDERINFO_FRFLAGOFF 8
122 #define FINDERINFO_FRVIEWOFF 14
124 /* invisible bit for dot files */
125 #define ATTRBIT_INVISIBLE (1 << 0)
126 #define FINDERINFO_INVISIBLE (1 << 14)
128 /* this is to prevent changing timezones from causing problems with
129 localtime volumes. the screw-up is 30 years. we use a delta of 5
131 #define TIMEWARP_DELTA 157680000
135 u_int32_t id, offset, len;
138 #if AD_VERSION == AD_VERSION1
139 static const struct entry entry_order[] = {
140 {ADEID_NAME, ADEDOFF_NAME_V1, ADEDLEN_INIT},
141 {ADEID_COMMENT, ADEDOFF_COMMENT_V1, ADEDLEN_INIT},
142 {ADEID_FILEI, ADEDOFF_FILEI, ADEDLEN_FILEI},
143 {ADEID_FINDERI, ADEDOFF_FINDERI_V1, ADEDLEN_FINDERI},
144 {ADEID_RFORK, ADEDOFF_RFORK_V1, ADEDLEN_INIT},
147 #else if AD_VERSION == AD_VERSION2
148 static const struct entry entry_order[] = {
149 {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT},
150 {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT},
151 {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI},
152 {ADEID_FINDERI, ADEDOFF_FINDERI_V2, ADEDLEN_FINDERI},
153 {ADEID_DID, ADEDOFF_DID, ADEDLEN_DID},
154 {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI},
155 {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT},
156 {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI},
157 {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT},
162 #if AD_VERSION == AD_VERSION2
165 static __inline__ int ad_v1tov2(struct adouble *ad, const char *path)
173 /* check to see if we should convert this header. */
174 if (!path || (ad->ad_version != AD_VERSION1))
177 /* convert from v1 to v2. what does this mean?
178 * 1) change FILEI into FILEDATESI
179 * 2) create space for SHORTNAME, AFPFILEI, DID, and PRODOSI
180 * 3) move FILEI attributes into AFPFILEI
181 * 4) initialize ACCESS field of FILEDATESI.
183 * so, we need 4*12 (entry ids) + 12 (shortname) + 4 (afpfilei) +
184 * 4 (did) + 8 (prodosi) = 76 more bytes. */
186 #define SHIFTDATA (AD_DATASZ2 - AD_DATASZ1)
188 /* bail if we can't get a lock */
189 if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0)
192 if ((fd = open(path, O_RDWR)) < 0)
195 if (gettimeofday(&tv, NULL) < 0)
198 if (fstat(fd, &st) ||
199 ftruncate(fd, st.st_size + SHIFTDATA) < 0) {
203 /* last place for failure. */
204 if ((void *) (buf = (char *)
205 mmap(NULL, st.st_size + SHIFTDATA,
206 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
211 off = ad->ad_eid[ADEID_RFORK].ade_off;
213 #ifdef USE_MMAPPED_HEADERS
214 /* okay, unmap our old ad header and point it to our local copy */
215 munmap(ad->ad_data, off);
219 /* move the RFORK. this assumes that the RFORK is at the end */
220 memmove(buf + off + SHIFTDATA, buf + off,
221 ad->ad_eid[ADEID_RFORK].ade_len);
223 /* now, fix up our copy of the header */
224 memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
226 /* replace FILEI with FILEDATESI */
227 ad_getattr(ad, &attr);
228 ad->ad_eid[ADEID_FILEDATESI].ade_off = ADEDOFF_FILEDATESI;
229 ad->ad_eid[ADEID_FILEDATESI].ade_len = ADEDLEN_FILEDATESI;
230 ad->ad_eid[ADEID_FILEI].ade_off = 0;
231 ad->ad_eid[ADEID_FILEI].ade_len = 0;
233 /* add in the new entries */
234 ad->ad_eid[ADEID_DID].ade_off = ADEDOFF_DID;
235 ad->ad_eid[ADEID_DID].ade_len = ADEDLEN_DID;
236 ad->ad_eid[ADEID_AFPFILEI].ade_off = ADEDOFF_AFPFILEI;
237 ad->ad_eid[ADEID_AFPFILEI].ade_len = ADEDLEN_AFPFILEI;
238 ad->ad_eid[ADEID_SHORTNAME].ade_off = ADEDOFF_SHORTNAME;
239 ad->ad_eid[ADEID_SHORTNAME].ade_len = ADEDLEN_INIT;
240 ad->ad_eid[ADEID_PRODOSFILEI].ade_off = ADEDOFF_PRODOSFILEI;
241 ad->ad_eid[ADEID_PRODOSFILEI].ade_len = ADEDLEN_PRODOSFILEI;
243 /* shift the old entries (NAME, COMMENT, FINDERI, RFORK) */
244 ad->ad_eid[ADEID_NAME].ade_off = ADEDOFF_NAME_V2;
245 ad->ad_eid[ADEID_COMMENT].ade_off = ADEDOFF_COMMENT_V2;
246 ad->ad_eid[ADEID_FINDERI].ade_off = ADEDOFF_FINDERI_V2;
247 ad->ad_eid[ADEID_RFORK].ade_off = ADEDOFF_RFORK_V2;
250 ad->ad_version = AD_VERSION2;
252 /* move our data buffer to make space for the new entries. */
253 memmove(buf + ADEDOFF_NAME_V2, buf + ADEDOFF_NAME_V1,
254 ADEDOFF_RFORK_V1 - ADEDOFF_NAME_V1);
256 /* now, fill in the space with appropriate stuff. we're
257 operating as a v2 file now. */
258 ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, tv.tv_sec);
259 memset(ad_entry(ad, ADEID_DID), 0, ADEDLEN_DID);
260 memset(ad_entry(ad, ADEID_AFPFILEI), 0, ADEDLEN_AFPFILEI);
261 ad_setattr(ad, attr);
262 memset(ad_entry(ad, ADEID_SHORTNAME), 0, ADEDLEN_SHORTNAME);
263 memset(ad_entry(ad, ADEID_PRODOSFILEI), 0, ADEDLEN_PRODOSFILEI);
265 /* rebuild the header and cleanup */
266 ad_rebuild_header(ad);
267 munmap(buf, st.st_size + SHIFTDATA);
269 ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
271 #ifdef USE_MMAPPED_HEADERS
272 /* now remap our header */
273 ad->ad_data = mmap(NULL, ADEDOFF_RFORK_V2, PROT_READ | PROT_WRITE,
274 (ad_getoflags(ad, ADFLAGS_HF) & O_RDWR) ? MAP_SHARED :
275 MAP_PRIVATE, ad->ad_hf.adf_fd, 0);
276 if (ad->ad_data == MAP_FAILED)
283 ftruncate(fd, st.st_size);
287 ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
294 /* read in the entries */
295 static __inline__ void parse_entries(struct adouble *ad, char *buf,
298 u_int32_t eid, len, off;
300 /* now, read in the entry bits */
301 for (; nentries > 0; nentries-- ) {
302 memcpy(&eid, buf, sizeof( eid ));
304 buf += sizeof( eid );
305 memcpy(&off, buf, sizeof( off ));
307 buf += sizeof( off );
308 memcpy(&len, buf, sizeof( len ));
310 buf += sizeof( len );
312 if ( 0 < eid && eid < ADEID_MAX ) {
313 ad->ad_eid[ eid ].ade_off = off;
314 ad->ad_eid[ eid ].ade_len = len;
316 syslog( LOG_DEBUG, "ad_refresh: nentries %hd eid %d\n",
323 /* this reads enough of the header so that we can figure out all of
324 * the entry lengths and offsets. once that's done, we just read/mmap
325 * the rest of the header in.
327 * NOTE: we're assuming that the resource fork is kept at the end of
328 * the file. also, mmapping won't work for the hfs fs until it
329 * understands how to mmap header files. */
330 static __inline__ int ad_header_read(struct adouble *ad)
332 #ifdef USE_MMAPPED_HEADERS
333 char buf[AD_ENTRY_LEN*ADEID_MAX];
335 char *buf = ad->ad_data;
339 static int warning = 0;
341 /* read the header */
342 if ( ad->ad_hf.adf_off != 0 ) {
343 if ( lseek( ad->ad_hf.adf_fd, 0L, SEEK_SET ) < 0L ) {
346 ad->ad_hf.adf_off = 0;
349 if (read( ad->ad_hf.adf_fd, buf, AD_HEADER_LEN) != AD_HEADER_LEN) {
355 ad->ad_hf.adf_off = AD_HEADER_LEN;
357 memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic ));
358 memcpy(&ad->ad_version, buf + ADEDOFF_VERSION,
359 sizeof( ad->ad_version ));
361 /* tag broken v1 headers. just assume they're all right.
362 * we detect two cases: null magic/version
363 * byte swapped magic/version
364 * XXX: in the future, you'll need the v1compat flag.
365 * (ad->ad_flags & ADFLAGS_V1COMPAT) */
366 if (!ad->ad_magic && !ad->ad_version) {
368 syslog(LOG_DEBUG, "notice: fixing up null v1 magic/version.");
371 ad->ad_magic = AD_MAGIC;
372 ad->ad_version = AD_VERSION1;
374 } else if ((ad->ad_magic == AD_MAGIC) &&
375 (ad->ad_version == AD_VERSION1)) {
377 syslog(LOG_DEBUG, "notice: fixing up byte-swapped v1 magic/version.");
382 ad->ad_magic = ntohl( ad->ad_magic );
383 ad->ad_version = ntohl( ad->ad_version );
386 if ((ad->ad_magic != AD_MAGIC) || ((ad->ad_version != AD_VERSION1)
387 #if AD_VERSION == AD_VERSION2
388 && (ad->ad_version != AD_VERSION2)
392 syslog(LOG_DEBUG, "ad_open: can't parse AppleDouble header.");
396 memcpy(ad->ad_filler, buf + ADEDOFF_FILLER, sizeof( ad->ad_filler ));
397 memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
398 nentries = ntohs( nentries );
400 /* read in all the entry headers. if we have more than the
401 * maximum, just hope that the rfork is specified early on. */
402 len = nentries*AD_ENTRY_LEN;
403 #ifdef USE_MMAPPED_HEADERS
404 if (len > sizeof(buf))
407 if (len + AD_HEADER_LEN > sizeof(ad->ad_data))
408 len = sizeof(ad->ad_data) - AD_HEADER_LEN;
409 buf += AD_HEADER_LEN;
411 if (read(ad->ad_hf.adf_fd, buf, len) != len) {
414 syslog(LOG_DEBUG, "ad_header_read: can't read entry info.");
417 ad->ad_hf.adf_off += len;
419 /* figure out all of the entry offsets and lengths. if we aren't
420 * able to read a resource fork entry, bail. */
421 parse_entries(ad, buf, nentries);
422 if (!ad_getentryoff(ad, ADEID_RFORK)
423 #ifndef USE_MMAPPED_HEADERS
424 || (ad_getentryoff(ad, ADEID_RFORK) > sizeof(ad->ad_data))
427 syslog(LOG_DEBUG, "ad_header_read: problem with rfork entry offset.");
431 /* read/mmap up to the beginning of the resource fork. */
432 #ifdef USE_MMAPPED_HEADERS
433 ad->ad_data = mmap(NULL, ad_getentryoff(ad, ADEID_RFORK),
434 PROT_READ | PROT_WRITE,
435 (ad_getoflags(ad, ADFLAGS_HF) & O_RDWR) ? MAP_SHARED :
436 MAP_PRIVATE, ad->ad_hf.adf_fd, 0);
437 if (ad->ad_data == MAP_FAILED)
441 len = ad_getentryoff(ad, ADEID_RFORK) - ad->ad_hf.adf_off;
442 if (read(ad->ad_hf.adf_fd, buf, len) != len) {
445 syslog(LOG_DEBUG, "ad_header_read: can't read in entries.");
450 /* fix up broken dates */
451 if (ad->ad_version == AD_VERSION1) {
455 if (fstat(ad->ad_hf.adf_fd, &st) < 0) {
456 return 1; /* fail silently */
459 /* check to see if the ad date is wrong. just see if we have
460 * a modification date in the future. */
461 if (((ad_getdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, &aint)) == 0) &&
462 (aint > TIMEWARP_DELTA + st.st_mtime)) {
463 ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, aint - AD_DATE_DELTA);
464 ad_getdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, &aint);
465 ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, aint - AD_DATE_DELTA);
466 ad_getdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, &aint);
467 ad_setdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, aint - AD_DATE_DELTA);
476 * Put the .AppleDouble where it needs to be:
480 * \ b/.AppleDouble/.Parent
483 ad_path( path, adflags )
487 static char pathbuf[ MAXPATHLEN + 1];
488 char c, *slash, buf[MAXPATHLEN + 1];
490 strncpy(buf, path, MAXPATHLEN);
491 if ( adflags & ADFLAGS_DIR ) {
492 strncpy( pathbuf, buf, MAXPATHLEN );
493 if ( *buf != '\0' ) {
494 strcat( pathbuf, "/" );
498 if (( slash = strrchr( buf, '/' )) != NULL ) {
501 strncpy( pathbuf, buf, MAXPATHLEN);
508 strncat( pathbuf, ".AppleDouble/", MAXPATHLEN - strlen(pathbuf));
509 strncat( pathbuf, slash, MAXPATHLEN - strlen(pathbuf));
515 * Support inherited protection modes for AppleDouble files. The supplied
516 * mode is ANDed with the parent directory's mask value in lieu of "umask",
517 * and that value is returned.
520 #define DEFMASK 7700 /* be conservative */
523 ad_mode( path, mode )
527 static char modebuf[ MAXPATHLEN + 1];
532 return( mode ); /* save on syscalls */
535 if ( strlen( path ) >= MAXPATHLEN ) {
536 return( mode & DEFMASK ); /* can't do it */
540 * For a path with directories in it, remove the final component
541 * (path or subdirectory name) to get the name we want to stat.
542 * For a path which is just a filename, use "." instead.
544 strcpy( modebuf, path );
545 if (( slash = strrchr( modebuf, '/' )) != NULL ) {
546 *slash = '\0'; /* remove pathname component */
548 modebuf[0] = '.'; /* use current directory */
552 if ( stat( modebuf, &stbuf ) != 0 ) {
553 return( mode & DEFMASK ); /* bail out... can't stat dir? */
556 return( mode & stbuf.st_mode );
560 * Use mkdir() with mode bits taken from ad_mode().
563 ad_mkdir( path, mode )
567 return mkdir( path, ad_mode( path, mode ) );
572 * It's not possible to open the header file O_RDONLY -- the read
573 * will fail and return an error. this refcounts things now.
575 int ad_open( path, adflags, oflags, mode, ad )
577 int adflags, oflags, mode;
580 const struct entry *eid;
586 if (ad->ad_inited != AD_INITED) {
589 adf_lock_init(&ad->ad_df);
590 adf_lock_init(&ad->ad_hf);
591 #ifdef USE_MMAPPED_HEADERS
592 ad->ad_data = MAP_FAILED;
594 ad->ad_inited = AD_INITED;
597 if (adflags & ADFLAGS_DF) {
598 if (ad_dfileno(ad) == -1) {
599 if (( ad->ad_df.adf_fd =
600 open( path, oflags, ad_mode( path, mode ) )) < 0 ) {
603 ad->ad_df.adf_off = 0;
604 ad->ad_df.adf_flags = oflags;
606 ad->ad_df.adf_refcount++;
609 if (adflags & ADFLAGS_HF) {
610 if (ad_hfileno(ad) == -1) {
611 ad_p = ad_path( path, adflags );
612 admode = ad_mode( ad_p, mode );
614 hoflags = oflags & ~O_CREAT;
615 if (( ad->ad_hf.adf_fd = open( ad_p, hoflags, admode )) < 0 ) {
616 if ( errno == ENOENT && hoflags != oflags ) {
618 * We're expecting to create a new adouble header file,
622 if (( ad->ad_hf.adf_fd = open( ad_p, oflags,
625 * Probably .AppleDouble doesn't exist, try to
628 if ((errno == ENOENT) &&
629 ((adflags & ADFLAGS_NOADOUBLE) == 0)) {
630 if (( slash = strrchr( ad_p, '/' )) == NULL ) {
631 ad_close( ad, adflags );
636 if ( ad_mkdir( ad_p, 0777 ) < 0 ) {
637 ad_close( ad, adflags );
641 if (( ad->ad_hf.adf_fd =
642 open( ad_p, oflags, ad_mode( ad_p, mode) )) < 0 ) {
643 ad_close( ad, adflags );
647 ad_close( ad, adflags );
651 ad->ad_hf.adf_flags = oflags;
653 ad_close( ad, adflags );
656 } else if ((fstat(ad->ad_hf.adf_fd, &st) == 0) &&
658 /* for 0 length files, treat them as new. */
659 ad->ad_hf.adf_flags = oflags;
661 ad->ad_hf.adf_flags = hoflags;
663 ad->ad_hf.adf_off = 0;
666 * This is a new adouble header file. Initialize the structure,
667 * instead of reading it.
669 memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
670 if ( ad->ad_hf.adf_flags & ( O_TRUNC | O_CREAT )) {
673 ad->ad_magic = AD_MAGIC;
674 ad->ad_version = AD_VERSION;
675 memset(ad->ad_filler, 0, sizeof( ad->ad_filler ));
677 #ifdef USE_MMAPPED_HEADERS
678 /* truncate the header file and mmap it. */
679 ftruncate(ad->ad_hf.adf_fd, AD_DATASZ);
680 ad->ad_data = mmap(NULL, AD_DATASZ, PROT_READ | PROT_WRITE,
681 MAP_SHARED, ad->ad_hf.adf_fd, 0);
682 if (ad->ad_data == MAP_FAILED) {
683 ad_close(ad, adflags);
687 memset(ad->ad_data, 0, sizeof(ad->ad_data));
692 ad->ad_eid[eid->id].ade_off = eid->offset;
693 ad->ad_eid[eid->id].ade_len = eid->len;
697 /* put something sane in the directory finderinfo */
698 if (adflags & ADFLAGS_DIR) {
699 /* set default view */
700 ashort = htons(FINDERINFO_CLOSEDVIEW);
701 memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF,
702 &ashort, sizeof(ashort));
704 /* set default creator/type fields */
705 memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,
707 memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,
711 /* make things invisible */
712 if ((*path == '.') && strcmp(path, ".") && strcmp(path, "..")) {
713 ashort = htons(ATTRBIT_INVISIBLE);
714 ad_setattr(ad, ashort);
715 ashort = htons(FINDERINFO_INVISIBLE);
716 memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,
717 &ashort, sizeof(ashort));
720 if (gettimeofday(&tv, NULL) < 0) {
721 ad_close(ad, adflags);
725 /* put something sane in the date fields */
726 ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, tv.tv_sec);
727 ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, tv.tv_sec);
728 ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, tv.tv_sec);
729 ad_setdate(ad, AD_DATE_BACKUP, AD_DATE_START);
733 * Read the adouble header in and parse it.
735 if ((ad_header_read( ad ) < 0)
736 #if AD_VERSION == AD_VERSION2
737 || (ad_v1tov2(ad, ad_p) < 0)
740 ad_close( ad, adflags );
745 ad->ad_hf.adf_refcount++;
751 /* to do this with mmap, we need the hfs fs to understand how to mmap
753 int ad_refresh(struct adouble *ad)
755 #ifdef USE_MMAPPED_HEADERS
759 if (ad->ad_hf.adf_fd < -1)
762 #ifdef USE_MMAPPED_HEADERS
763 if (ad->ad_data == MAP_FAILED)
766 /* re-read the header */
767 off = ad_getentryoff(ad, ADEID_RFORK);
768 memcpy(&nentries, ad->ad_data + ADEDOFF_NENTRIES, sizeof(nentries));
769 nentries = ntohs(nentries);
770 parse_entries(ad, ad->ad_data + AD_HEADER_LEN, nentries);
772 /* check to see if something screwy happened */
773 if (!ad_getentryoff(ad, ADEID_RFORK))
776 /* if there's a length discrepancy, remap the header. this shouldn't
777 * really ever happen. */
778 if (off != ad_getentryoff(ad, ADEID_RFORK)) {
779 char *buf = ad->ad_data;
781 ad->ad_data = mmap(NULL, ad_getentryoff(ad, ADEID_RFORK),
782 PROT_READ | PROT_WRITE,
783 (ad_getoflags(ad, ADFLAGS_HF) & O_RDWR) ?
784 MAP_SHARED : MAP_PRIVATE, ad->ad_hf.adf_fd, 0);
785 if (ad->ad_data == MAP_FAILED) {
794 return ad_header_read(ad);