diff --git a/build.vc10/daemon.vcxproj b/build.vc10/daemon.vcxproj
index 0b7552f..7035e57 100644
--- a/build.vc10/daemon.vcxproj
+++ b/build.vc10/daemon.vcxproj
@@ -219,6 +219,7 @@
+
diff --git a/build.vc10/daemon.vcxproj.filters b/build.vc10/daemon.vcxproj.filters
index 0538ee1..8390631 100644
--- a/build.vc10/daemon.vcxproj.filters
+++ b/build.vc10/daemon.vcxproj.filters
@@ -107,6 +107,9 @@
Source Files
+
+ Source Files
+
diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
index 6c017d3..e8edcc3 100644
--- a/daemon/daemon_debug.c
+++ b/daemon/daemon_debug.c
@@ -279,6 +279,7 @@ const char* opcode2string(DWORD opcode)
case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY";
case NFS41_FILE_SET: return "NFS41_FILE_SET";
case NFS41_EA_SET: return "NFS41_EA_SET";
+ case NFS41_SYMLINK: return "NFS41_SYMLINK";
case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
default: return "UNKNOWN";
}
diff --git a/daemon/symlink.c b/daemon/symlink.c
new file mode 100644
index 0000000..680b64f
--- /dev/null
+++ b/daemon/symlink.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2010
+ * The Regents of the University of Michigan
+ * All Rights Reserved
+ *
+ * Permission is granted to use, copy, create derivative works, and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization. If
+ * the above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * This software is provided as is, without representation or warranty
+ * of any kind either express or implied, including without limitation
+ * the implied warranties of merchantability, fitness for a particular
+ * purpose, or noninfringement. The Regents of the University of
+ * Michigan shall not be liable for any damages, including special,
+ * indirect, incidental, or consequential damages, with respect to any
+ * claim arising out of or in connection with the use of the software,
+ * even if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+
+#include
+#include
+
+#include "upcall.h"
+#include "util.h"
+#include "daemon_debug.h"
+
+
+/* NFS41_SYMLINK */
+int parse_symlink(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
+{
+ symlink_upcall_args *args = &upcall->args.symlink;
+ int status;
+
+ status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
+ if (status) goto out;
+ status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *));
+ if (status) goto out;
+ status = get_name(&buffer, &length, &args->path);
+ if (status) goto out;
+ status = safe_read(&buffer, &length, &args->set, sizeof(BOOLEAN));
+ if (status) goto out;
+
+ if (args->set)
+ status = get_name(&buffer, &length, &args->target_set);
+ else
+ args->target_set = NULL;
+
+ dprintf(1, "parsing NFS41_SYMLINK: root=0x%p open_state=0x%p "
+ "path='%s' set=%u target='%s'\n", args->root, args->state,
+ args->path, args->set, args->target_set);
+out:
+ return status;
+}
+
+int handle_symlink(nfs41_upcall *upcall)
+{
+ return NO_ERROR;
+}
+
+int marshall_symlink(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
+{
+ symlink_upcall_args *args = &upcall->args.symlink;
+ unsigned short len = (args->target_get.len + 1) * sizeof(WCHAR);
+ int status = NO_ERROR;
+
+ if (args->set)
+ goto out;
+
+ status = safe_write(&buffer, length, &len, sizeof(len));
+ if (status) goto out;
+
+ if (*length <= len || !MultiByteToWideChar(CP_UTF8, 0,
+ args->target_get.path, args->target_get.len,
+ (LPWSTR)buffer, len / sizeof(WCHAR))) {
+ status = ERROR_BUFFER_OVERFLOW;
+ goto out;
+ }
+out:
+ return status;
+}
diff --git a/daemon/upcall.c b/daemon/upcall.c
index b5168d6..316910a 100644
--- a/daemon/upcall.c
+++ b/daemon/upcall.c
@@ -76,6 +76,10 @@ int parse_setexattr(unsigned char*, uint32_t, nfs41_upcall*);
int handle_setexattr(nfs41_upcall*);
int marshall_setexattr(unsigned char*, uint32_t*, nfs41_upcall*);
+int parse_symlink(unsigned char*, uint32_t, nfs41_upcall*);
+int handle_symlink(nfs41_upcall*);
+int marshall_symlink(unsigned char*, uint32_t*, nfs41_upcall*);
+
int parse_volume(unsigned char*, uint32_t, nfs41_upcall*);
int handle_volume(nfs41_upcall*);
int marshall_volume(unsigned char*, uint32_t*, nfs41_upcall*);
@@ -93,6 +97,7 @@ static const nfs41_upcall_op g_upcall_op_table[] = {
{ parse_getattr, handle_getattr, marshall_getattr, NULL },
{ parse_setattr, handle_setattr, marshall_setattr, NULL },
{ parse_setexattr, handle_setexattr, marshall_setexattr, NULL },
+ { parse_symlink, handle_symlink, marshall_symlink, NULL },
{ parse_volume, handle_volume, marshall_volume, NULL },
{ NULL, NULL, NULL, NULL }, /* NFS41_SHUTDOWN */
{ NULL, NULL, NULL, NULL }, /* INVALID_OPCODE */
diff --git a/daemon/upcall.h b/daemon/upcall.h
index e07bd91..1b45de3 100644
--- a/daemon/upcall.h
+++ b/daemon/upcall.h
@@ -134,6 +134,15 @@ typedef struct __readdir_upcall_args {
BOOLEAN single;
} readdir_upcall_args;
+typedef struct __symlink_upcall_args {
+ nfs41_abs_path target_get;
+ const char *target_set;
+ nfs41_root *root;
+ nfs41_open_state *state;
+ const char *path;
+ BOOLEAN set;
+} symlink_upcall_args;
+
typedef struct __volume_upcall_args {
nfs41_root *root;
FS_INFORMATION_CLASS query;
@@ -157,6 +166,7 @@ typedef union __upcall_args {
setattr_upcall_args setattr;
setexattr_upcall_args setexattr;
readdir_upcall_args readdir;
+ symlink_upcall_args symlink;
volume_upcall_args volume;
} upcall_args;