$NetBSD: patch-br,v 1.6 2011/10/06 02:19:06 manu Exp $

Use linkat(2) if available so that we can make a hardlink to symlink 
itself, instead of symlink destination, like link(2) does. This is
required to support moving symlinks on distributed volumes, as
glusterfsd really wants to hardlink the symlink and not its target. 

If linkat(2) is inavailable, then moving a symlink on distributed
volumes fails.

Correctly cast gfid when producing inode to avoid it getting garbled

Ignore .attribute because chaos occurs if it gets distributed

--- xlators/storage/posix/src/posix.c.orig	2011-11-14 14:46:03.000000000 +0100
+++ xlators/storage/posix/src/posix.c	2011-12-09 03:45:17.000000000 +0100
@@ -36,8 +36,12 @@
 #ifndef GF_BSD_HOST_OS
 #include <alloca.h>
 #endif /* GF_BSD_HOST_OS */
 
+#ifdef HAVE_LINKAT
+#include <fcntl.h>
+#endif /* HAVE_LINKAT */
+
 #include "glusterfs.h"
 #include "md5.h"
 #include "checksum.h"
 #include "dict.h"
@@ -286,9 +290,9 @@
         int i = 0;
 
         /* consider least significant 8 bytes of value out of gfid */
         for (i = 15; i > (15 - 8); i--) {
-                temp_ino += buf->ia_gfid[i] << j;
+                temp_ino += (uint64_t)(buf->ia_gfid[i]) << j;
                 j += 8;
         }
 
         buf->ia_ino = temp_ino;
@@ -1311,8 +1315,13 @@
                         loc->path, strerror (op_errno));
                 goto out;
         }
 
+#ifdef __NetBSD__
+	if (S_ISFIFO(mode))
+		op_ret = mkfifo (real_path, mode);
+	else
+#endif /* __NetBSD__ */
         op_ret = mknod (real_path, mode, dev);
 
         if (op_ret == -1) {
                 op_errno = errno;
@@ -2204,9 +2213,20 @@
                         newparentpath, strerror (op_errno));
                 goto out;
         }
 
+#ifdef HAVE_LINKAT
+	/*
+	 * On most systems (Linux being the notable exception), link(2)
+	 * first resolves symlinks. If the target is a directory or
+	 * is nonexistent, it will fail. linkat(2) operates on the 
+	 * symlink instead of its target when the AT_SYMLINK_FOLLOW
+	 * flag is not supplied.
+	 */
+        op_ret = linkat (AT_FDCWD, real_oldpath, AT_FDCWD, real_newpath, 0);
+#else
         op_ret = link (real_oldpath, real_newpath);
+#endif
         if (op_ret == -1) {
                 op_errno = errno;
                 gf_log (this->name, GF_LOG_ERROR,
                         "link %s to %s failed: %s",
@@ -4329,8 +4349,22 @@
                 if ((!strcmp (real_path, base_path))
                     && (!strcmp (entry->d_name, GF_REPLICATE_TRASH_DIR)))
                         continue;
 
+#ifdef __NetBSD__
+		/*
+		 * NetBSD with UFS1 backend uses backing files for
+		 * extended attributes. They can be found in a
+		 * .attribute file located at the root of the filesystem
+		 * We hide it to glusterfs clients, since chaos will occur 
+		 * when the cluster/dht xlator decides to distribute
+		 * exended attribute backing file accross storage servers.
+		 */ 
+	        if ((!strcmp(real_path, base_path))
+	            && (!strcmp(entry->d_name, ".attribute")))
+	                continue;
+#endif /* __NetBSD__ */
+
                 if ((!strcmp (real_path, base_path))
                     && (!strncmp (GF_HIDDEN_PATH, entry->d_name,
                                   strlen (GF_HIDDEN_PATH)))) {
                         snprintf (hidden_path, PATH_MAX, "%s/%s", real_path,
@@ -4455,14 +4489,15 @@
 
         /* pick ENOENT to indicate EOF */
         op_errno = errno;
 
+        list_for_each_entry (tmp_entry, &entries.list, list) {
+                strcpy (entry_path + real_path_len + 1,
+                        tmp_entry->d_name);
+                posix_lstat_with_gfid (this, entry_path, &stbuf);
+                tmp_entry->d_ino = stbuf.ia_ino;
+
         if (whichop == GF_FOP_READDIRP) {
-                list_for_each_entry (tmp_entry, &entries.list, list) {
-                        strcpy (entry_path + real_path_len + 1,
-                                tmp_entry->d_name);
-                        posix_lstat_with_gfid (this, entry_path, &stbuf);
-                        tmp_entry->d_ino = stbuf.ia_ino;
                         tmp_entry->d_stat = stbuf;
                 }
         }
 
