Workaround for Network Trash and system without byte locking (broken nfs/afs)
mangle OS9 "Network Trash Folder/Trash Can #2" name to
"Network Trash Folder/Trash Can #2.<client ip>.<tcp port>"
So multiple clients can share the same volume and have a working trash.

Index: etc/afpd/directory.c
===================================================================
RCS file: /cvsroot/netatalk/netatalk/etc/afpd/directory.c,v
retrieving revision 1.71.2.4.2.12
diff -u -r1.71.2.4.2.12 directory.c
--- etc/afpd/directory.c	11 Mar 2004 16:16:40 -0000	1.71.2.4.2.12
+++ etc/afpd/directory.c	21 Apr 2004 12:42:03 -0000
@@ -554,6 +554,7 @@
  * attempt to extend the current dir. tree to include path
  * as a side-effect, movecwd to that point and return the new dir
  */
+
 static struct dir *
             extenddir( vol, dir, path )
 struct vol	*vol;
@@ -563,7 +564,25 @@
     char *save_m_name;
 
     if ( path->u_name == NULL) {
-        path->u_name = mtoupath(vol, path->m_name, dir->d_did, (path->m_type==3) );
+#ifdef DISABLE_LOCKING
+        int l = strlen(TRASH_PREFIX);
+        /* XXX replace mac name with unix name */
+    	if (vol->v_trash_id && vol->v_trash_id  == dir->d_did && vol->v_ip &&
+    	       !strncmp(TRASH_PREFIX , path->m_name, l ) )
+    	{
+    	    static char temp[MAXPATHLEN + 1];
+    	    char *u;
+
+    	    strcpy(temp, path->m_name);
+    	    u = temp +l;
+    	    strcat(temp, ".");
+    	    strcat(temp, vol->v_ip);
+    	    path->u_name = temp;
+    	
+    	}
+        else 
+#endif
+            path->u_name = mtoupath(vol, path->m_name, dir->d_did, (path->m_type==3) );
     }
     path->dir = NULL;
 
Index: etc/afpd/enumerate.c
===================================================================
RCS file: /cvsroot/netatalk/netatalk/etc/afpd/enumerate.c,v
retrieving revision 1.39.2.2.2.4
diff -u -r1.39.2.2.2.4 enumerate.c
--- etc/afpd/enumerate.c	11 Mar 2004 02:01:59 -0000	1.39.2.2.2.4
+++ etc/afpd/enumerate.c	21 Apr 2004 12:42:04 -0000
@@ -54,9 +54,39 @@
     if (id == 0) {
         return NULL;
     }
+    
+#ifdef DISABLE_LOCKING
+    if (!path->m_name) {
+        int l = strlen(TRASH_PREFIX);
+        /* XXX */
+    	if (vol->v_trash_id && vol->v_trash_id  == dir->d_did && vol->v_ip &&
+    	       !strncmp(TRASH_PREFIX , upath, l ) )
+    	{
+    	    static char temp[MAXPATHLEN + 1];
+    	    char *u;
+
+    	    strcpy(temp, upath);
+    	    u = temp +l;
+    	    
+    	    while (*u >= '0' && *u <= '9') {
+    	        u++;
+    	    }
+    	    if (*u == '.') {
+    	        *u = '\0';
+    	    }
+    	    path->m_name = temp; 
+    	}
+    	    
+        else if(!(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
+           return NULL;
+        }
+    }
+#else 
     if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
-        return NULL;
+       return NULL;
     }
+#endif
+    
     name  = path->m_name;    
     if ((cdir = dirnew(name, upath)) == NULL) {
         LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
@@ -185,6 +215,32 @@
     return name;
 }
 
+#ifdef DISABLE_LOCKING
+/* ----------------------------- */
+int check_trash(const struct vol *vol, char *name)
+{
+int l = strlen(TRASH_PREFIX);
+char *u;
+
+    if (strncmp(TRASH_PREFIX , name, l)) 
+        return 0;
+    /* */
+    u = name +l;
+    while (*u >= '0' && *u <= '9') {
+        u++;
+    }
+
+    if (u == name +l)
+        return 0;
+
+    if (*u == '.' && !strcmp(vol->v_ip, u +1)) {
+        return 0;
+    }
+    /* hide this one */
+    return 1;
+}
+#endif
+
 /* ----------------------------- */
 int 
 for_each_dirent(const struct vol *vol, char *name, dir_loop fn, void *data)
@@ -193,15 +249,28 @@
     struct dirent	*de;
     char            *m_name;
     int             ret;
+#ifdef DISABLE_LOCKING
+    int             mangle_trash = 0;
+#endif
     
     if (NULL == ( dp = opendir( name)) ) {
         return -1;
     }
+
+#ifdef DISABLE_LOCKING
+    if (vol->v_trash_id && vol->v_trash_id == curdir->d_did && !strcmp(name, ".")) {
+        mangle_trash = 1;
+    }
+#endif    
     ret = 0;
     for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
         if (!(m_name = check_dirent(vol, de->d_name)))
             continue;
 
+#ifdef DISABLE_LOCKING
+        if (mangle_trash && check_trash(vol, de->d_name))
+            continue;
+#endif
         ret++;
         if (fn && fn(de,m_name, data) < 0) {
            closedir(dp);
Index: etc/afpd/volume.c
===================================================================
RCS file: /cvsroot/netatalk/netatalk/etc/afpd/volume.c,v
retrieving revision 1.51.2.7.2.28
diff -u -r1.51.2.7.2.28 volume.c
--- etc/afpd/volume.c	6 Apr 2004 23:29:37 -0000	1.51.2.7.2.28
+++ etc/afpd/volume.c	21 Apr 2004 12:42:05 -0000
@@ -73,7 +73,11 @@
 
 static struct vol *Volumes = NULL;
 static u_int16_t	lastvid = 0;
-static char		*Trash = "\02\024Network Trash Folder";
+
+/* type, len, name */
+static char		*Trash2 = "\02\024Network Trash Folder";
+/* type, hint (4 bytes), len (2bytes), name */
+static char		*Trash3 = "\03\0\0\0\0\0\024Network Trash Folder";
 
 static struct extmap	*Extmap = NULL, *Defextmap = NULL;
 static int              Extmap_cnt;
@@ -1038,6 +1042,10 @@
     free(vol->v_forceuid);
     free(vol->v_forcegid);
 #endif /* FORCE_UIDGID */
+
+#ifdef DISABLE_LOCKING
+    free(vol->v_ip);
+#endif    
 }
 
 /* ------------------------------- */
@@ -1730,9 +1738,31 @@
 		goto openvol_err;
 	    }
 	}
-	else {
-            p = Trash;
-            cname( volume, volume->v_dir, &p );
+#ifndef DISABLE_LOCKING	
+	else 
+#endif	
+        {
+            struct path *s_path;
+
+            /* use the right name format */
+            p = (afp_version>= 30)?Trash3:Trash2;
+            s_path = cname( volume, volume->v_dir, &p );
+#ifdef DISABLE_LOCKING
+            if (s_path && *s_path->m_name == '\0' ) {
+                /* XXXX should do the same with ASP, could use volxlate but there's ':' in $p */
+                if (obj->proto == AFPPROTO_DSI) {
+                    DSI *dsi = obj->handle;
+                
+                    /* cname moved into dest folder */
+                    volume->v_trash_id = curdir->d_did;
+                    volume->v_ip = malloc(MAXPATHLEN +1);
+                    if (volume->v_ip) {
+                        sprintf(volume->v_ip, "%s.%u", inet_ntoa(dsi->client.sin_addr),
+                              ntohs(dsi->client.sin_port));
+                    }
+                }
+            }
+#endif
         }
         return( AFP_OK );
     }
Index: etc/afpd/volume.h
===================================================================
RCS file: /cvsroot/netatalk/netatalk/etc/afpd/volume.h,v
retrieving revision 1.19.2.5.2.6
diff -u -r1.19.2.5.2.6 volume.h
--- etc/afpd/volume.h	11 Mar 2004 02:02:04 -0000	1.19.2.5.2.6
+++ etc/afpd/volume.h	21 Apr 2004 12:42:05 -0000
@@ -81,6 +81,12 @@
     /* adouble indirection */
     int                 (*validupath)(const struct vol *, const char *);
     char                *(*ad_path)(const char *, int);
+
+#ifdef DISABLE_LOCKING
+    /* for OS 9 trash when there's no working byte locking (afs, nfs) */
+    cnid_t		v_trash_id;
+    char		*v_ip;
+#endif    
 };
 
 #ifdef NO_LARGE_VOL_SUPPORT
@@ -167,6 +173,8 @@
 #define VOLPBIT_BSIZE   11        /* block size */
 
 
+#define TRASH_PREFIX "Trash Can #"
+
 #define vol_noadouble(vol) (((vol)->v_flags & AFPVOL_NOADOUBLE) ? \
 			    ADFLAGS_NOADOUBLE : 0)
 #ifdef AFP3x
