/*
- * $Id: directory.c,v 1.71.2.4.2.6 2004-01-03 22:21:08 didg Exp $
+ * $Id: directory.c,v 1.71.2.4.2.7 2004-02-06 13:39:51 bfernhomberg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
struct stat *st = &path->st;
ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev,
- st->st_ino, curdir->d_did, vol->v_stamp);
+ st->st_ino, curdir->d_did, curdir->d_parent->d_did, vol->v_stamp);
}
ad_flush( &ad, ADFLAGS_HF );
ad_getentrylen( &ad, ADEID_NAME ));
ad_setid( &ad, (vol->v_flags & AFPVOL_NODEV)?0:s_path->st.st_dev,
- s_path->st.st_ino, dir->d_did, vol->v_stamp);
+ s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
ad_flush( &ad, ADFLAGS_HF );
ad_close( &ad, ADFLAGS_HF );
/*
- * $Id: file.c,v 1.92.2.2.2.10 2004-02-06 02:32:15 didg Exp $
+ * $Id: file.c,v 1.92.2.2.2.11 2004-02-06 13:39:51 bfernhomberg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
#if AD_VERSION > AD_VERSION1
dev_t dev;
ino_t ino;
+cnid_t a_did;
char stamp[ADEDLEN_PRIVSYN];
/* look in AD v2 header
* note inode and device are opaques and not in network order
memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
-
- if ( ((vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
- && ino == st->st_ino &&
- !memcmp(vol->v_stamp, stamp, sizeof(stamp)) )
- {
- memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
- return aint;
+ if (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)) {
+ memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
+
+ if ( ((vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
+ && ino == st->st_ino && a_did == did &&
+ !memcmp(vol->v_stamp, stamp, sizeof(stamp)) &&
+ (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)) )
+ {
+ memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
+ return aint;
+ }
}
}
}
/* update the ressource fork
* for a folder adp is always null
*/
- ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, vol->v_stamp);
+ ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
ad_flush(adp, ADFLAGS_HF);
}
#endif
return afp_errno;
}
+static int
+reenumerate_id(const struct vol *vol, char *name, cnid_t did)
+{
+ DIR *dp;
+ struct dirent *de;
+ int ret;
+ struct stat st;
+ cnid_t aint;
+ struct adouble ad;
+
+
+ if (vol->v_cdb != NULL) {
+ return -1;
+ }
+ if (NULL == ( dp = opendir( name)) ) {
+ return -1;
+ }
+ ret = 0;
+ for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
+ if (NULL == check_dirent(vol, de->d_name))
+ continue;
+
+ if ( stat(de->d_name, &st)<0 )
+ continue;
+
+ /* update or add to cnid */
+ aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
+
+#if AD_VERSION > AD_VERSION1
+ if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
+ ad_init(&ad, 0); /* OK */
+ if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
+ continue;
+ }
+ else {
+ ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
+ ad_flush(&ad, ADFLAGS_HF);
+ ad_close(&ad, ADFLAGS_HF);
+ }
+ }
+#endif /* AD_VERSION > AD_VERSION1 */
+
+ ret++;
+ }
+ closedir(dp);
+ return ret;
+}
+
+
/* ------------------------------
resolve a file id */
int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
struct dir *dir;
char *upath;
struct path path;
- int err, buflen;
+ int err, buflen, retry=0;
cnid_t id, cnid;
u_int16_t vid, bitmap;
ibuf += sizeof(id);
cnid = id;
+retry:
if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
}
return AFPERR_NOID; /* idem AFPERR_PARAM */
}
path.u_name = upath;
- if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
+ if (movecwd(vol, dir) < 0) {
+ switch (errno) {
+ case EACCES:
+ case EPERM:
+ return AFPERR_ACCESS;
+ case ENOENT:
+ return AFPERR_NOID;
+ default:
+ return AFPERR_PARAM;
+ }
+ }
+
+ if ( of_stat(&path) < 0 ) {
+ if ( errno == ENOENT && !retry) {
+ /* cnid db is out of sync, reenumerate the directory and updated ids */
+ reenumerate_id(vol, ".", id);
+ id = cnid;
+ retry = 1;
+ goto retry;
+ }
switch (errno) {
case EACCES:
case EPERM:
return AFPERR_PARAM;
}
}
+
/* directories are bad */
if (S_ISDIR(path.st.st_mode))
return AFPERR_BADTYPE;
/*
- * $Id: adouble.h,v 1.21.6.6 2004-01-31 14:26:24 bfernhomberg Exp $
+ * $Id: adouble.h,v 1.21.6.7 2004-02-06 13:39:52 bfernhomberg Exp $
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*
#define ADEID_PRIVDEV 16
#define ADEID_PRIVINO 17
#define ADEID_PRIVSYN 18 /* in synch with database */
+#define ADEID_PRIVID 19
#define AD_DEV 0x80444556
#define AD_INO 0x80494E4F
#define AD_SYN 0x8053594E
-#define ADEID_MAX 19
+#define AD_ID 0x8053567E
+#define ADEID_MAX 20
#endif
/* magic */
#define ADEDLEN_PRIVDEV 8
#define ADEDLEN_PRIVINO 8
#define ADEDLEN_PRIVSYN 8
+#define ADEDLEN_PRIVID 4
#define ADEID_NUM_V1 5
-#define ADEID_NUM_V2 12
+#define ADEID_NUM_V2 13
/* 589 */
#define AD_DATASZ1 (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT +ADEDLEN_FILEI +ADEDLEN_FINDERI+\
#endif
#define AD_NEWSZ2 (ADEDLEN_DID + ADEDLEN_AFPFILEI +ADEDLEN_SHORTNAME +ADEDLEN_PRODOSFILEI \
-+ADEDLEN_PRIVDEV +ADEDLEN_PRIVINO +ADEDLEN_PRIVSYN)
++ADEDLEN_PRIVDEV +ADEDLEN_PRIVINO +ADEDLEN_PRIVSYN+ ADEDLEN_PRIVID)
/* 725 */
#define AD_DATASZ2 (AD_DATASZ1 + AD_NEWSZ2 + (ADEID_NUM_V2 -ADEID_NUM_V1)*AD_ENTRY_LEN)
-#if AD_DATASZ2 != 725
+#if AD_DATASZ2 != 741
#error bad size for AD_DATASZ2
#endif
extern int ad_getattr __P((const struct adouble *, u_int16_t *));
#if AD_VERSION == AD_VERSION2
-extern int ad_setid __P((struct adouble *, const dev_t dev,const ino_t ino, const u_int32_t, const void *));
+extern int ad_setid __P((struct adouble *, const dev_t dev,const ino_t ino, const u_int32_t, const u_int32_t, const void *));
#else
#define ad_setid(a, b, c)
#endif
/*
- * $Id: ad_attr.c,v 1.4.8.2 2004-01-03 22:21:09 didg Exp $
+ * $Id: ad_attr.c,v 1.4.8.3 2004-02-06 13:39:52 bfernhomberg Exp $
*/
#ifdef HAVE_CONFIG_H
* save file/folder ID in AppleDoubleV2 netatalk private parameters
*/
#if AD_VERSION == AD_VERSION2
-int ad_setid (struct adouble *adp, const dev_t dev, const ino_t ino , const u_int32_t id, const void *stamp)
+int ad_setid (struct adouble *adp, const dev_t dev, const ino_t ino , const u_int32_t id, const cnid_t did, const void *stamp)
{
if (adp->ad_flags == AD_VERSION2 && sizeof(dev_t) == ADEDLEN_PRIVDEV && sizeof(ino_t) == ADEDLEN_PRIVINO)
{
ad_setentrylen( adp, ADEID_PRIVINO, sizeof(ino_t));
memcpy(ad_entry( adp, ADEID_PRIVINO ), &ino, sizeof(ino_t));
- ad_setentrylen( adp, ADEID_DID, sizeof(id));
- memcpy(ad_entry( adp, ADEID_DID ), &id, sizeof(id));
+ ad_setentrylen( adp, ADEID_PRIVID, sizeof(id));
+ memcpy(ad_entry( adp, ADEID_PRIVID ), &id, sizeof(id));
+
+ ad_setentrylen( adp, ADEID_DID, sizeof(did));
+ memcpy(ad_entry( adp, ADEID_DID ), &did, sizeof(did));
ad_setentrylen( adp, ADEID_PRIVSYN, ADEDLEN_PRIVSYN);
memcpy(ad_entry( adp, ADEID_PRIVSYN ), stamp, ADEDLEN_PRIVSYN);
/*
- * $Id: ad_flush.c,v 1.6.6.1 2003-09-09 16:42:21 didg Exp $
+ * $Id: ad_flush.c,v 1.6.6.2 2004-02-06 13:39:52 bfernhomberg Exp $
*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
static const u_int32_t set_eid[] = {
0,1,2,3,4,5,6,7,8,
9,10,11,12,13,14,15,
-AD_DEV, AD_INO, AD_SYN
+AD_DEV, AD_INO, AD_SYN, AD_ID
};
#define EID_DISK(a) (set_eid[a])
/*
- * $Id: ad_open.c,v 1.30.6.5 2004-01-03 22:16:32 didg Exp $
+ * $Id: ad_open.c,v 1.30.6.6 2004-02-06 13:39:52 bfernhomberg Exp $
*
* Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
* Copyright (c) 1990,1991 Regents of The University of Michigan.
#define ADEDOFF_PRIVDEV (ADEDOFF_PRODOSFILEI + ADEDLEN_PRODOSFILEI)
#define ADEDOFF_PRIVINO (ADEDOFF_PRIVDEV + ADEDLEN_PRIVDEV)
#define ADEDOFF_PRIVSYN (ADEDOFF_PRIVINO + ADEDLEN_PRIVINO)
+#define ADEDOFF_PRIVID (ADEDOFF_PRIVSYN + ADEDLEN_PRIVSYN)
-#define ADEDOFF_RFORK_V2 (ADEDOFF_PRIVSYN + ADEDLEN_PRIVSYN)
+#define ADEDOFF_RFORK_V2 (ADEDOFF_PRIVID + ADEDLEN_PRIVID)
/* we keep local copies of a bunch of stuff so that we can initialize things
* correctly. */
return ADEID_PRIVINO;
if (eid == AD_SYN)
return ADEID_PRIVSYN;
+ if (eid == AD_ID)
+ return ADEID_PRIVID;
return 0;
}
{ADEID_PRIVDEV, ADEDOFF_PRIVDEV, ADEDLEN_INIT},
{ADEID_PRIVINO, ADEDOFF_PRIVINO, ADEDLEN_INIT},
{ADEID_PRIVSYN, ADEDOFF_PRIVSYN, ADEDLEN_INIT},
+ {ADEID_PRIVID, ADEDOFF_PRIVID, ADEDLEN_INIT},
{ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT},
{0, 0, 0}
#if AD_VERSION == AD_VERSION2
+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;
+
+ /* check to see if we should convert this header. */
+ if (!path || (ad->ad_version != AD_VERSION2))
+ 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;
+
+ if ((fd = open(path, O_RDWR)) < 0)
+ goto bail_lock;
+
+ if (fstat(fd, &st) ||
+ sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
+ goto bail_open;
+ }
+ if (st.st_size > 0x7fffffff) {
+ LOG(log_debug, logtype_default, "ad_update: file '%s' too big for update.", path);
+ goto bail_truncate;
+ }
+ /* last place for failure. */
+ if ((void *) (buf = (char *)
+ mmap(NULL, st.st_size + shiftdata,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
+ MAP_FAILED) {
+ goto bail_truncate;
+ }
+
+ off = ad->ad_eid[ADEID_RFORK].ade_off;
+
+ /* 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);
+ close(fd);
+
+ /* 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 */
+ ad_flush(ad, ADFLAGS_HF );
+ ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
+
+ LOG(log_debug, logtype_default, "updated AD2 header %s", path);
+
+ return 0;
+
+bail_truncate:
+ sys_ftruncate(fd, st.st_size);
+bail_open:
+ close(fd);
+bail_lock:
+ ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
+bail_err:
+ return -1;
+}
+
+
/* FIXME work only if < 2GB */
static int ad_v1tov2(struct adouble *ad, const char *path)
{
ad->ad_eid[ADEID_PRIVINO].ade_len = ADEDLEN_INIT;
ad->ad_eid[ADEID_PRIVSYN].ade_off = ADEDOFF_PRIVSYN;
ad->ad_eid[ADEID_PRIVSYN].ade_len = ADEDLEN_INIT;
+ ad->ad_eid[ADEID_PRIVID].ade_off = ADEDOFF_PRIVID;
+ ad->ad_eid[ADEID_PRIVID].ade_len = ADEDLEN_INIT;
/* shift the old entries (NAME, COMMENT, FINDERI, RFORK) */
ad->ad_eid[ADEID_NAME].ade_off = ADEDOFF_NAME_V2;
/* Read the adouble header in and parse it.*/
if ((ad_header_read( ad , &st) < 0)
#if AD_VERSION == AD_VERSION2
- || (ad_v1tov2(ad, ad_p) < 0)
+ || (ad_v1tov2(ad, ad_p) < 0) || (ad_update(ad, ad_p) < 0)
#endif /* AD_VERSION == AD_VERSION2 */
) {
ad_close( ad, adflags );