summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdiskfs/file-inv-trans.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/libdiskfs/file-inv-trans.c b/libdiskfs/file-inv-trans.c
index 4a6752bb..6838a4a6 100644
--- a/libdiskfs/file-inv-trans.c
+++ b/libdiskfs/file-inv-trans.c
@@ -17,3 +17,77 @@
#include "priv.h"
#include "fs_S.h"
+
+/* Implement fs.defs:file_invoke_translator as described in <hurd/fs.defs>. */
+kern_return_t
+diskfs_S_file_invoke_translator (struct protid *cred,
+ int flags,
+ retry_type *retry,
+ char *retry_name,
+ mach_port_t *retrypt,
+ mach_msg_type_name_t *retrypttype)
+{
+ error_t error = 0;
+ mode_t type;
+ struct node *np;
+
+ /* This code is very similar (but subtly different) from
+ dir-pathtrans.c and fsys-getroot.c. A way should be found to
+ combine them. */
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ flags &= O_HURD;
+
+ np = cred->po->np;
+
+ mutex_lock (&np->lock);
+
+ type = np->dn_stat.st_mode & S_IFMT;
+
+ repeat_transcheck:
+ /* Ignore O_NOTRANS in the following check */
+ if (diskfs_node_translated (np) || np->translator.control != MACH_PORT_NULL)
+ {
+ mach_port_t control = np->translator.control;
+
+ if (control == MACH_PORT_NULL)
+ {
+ /* This use of _diskfs_dotdot_file is completely and utterly
+ bogus. XXX */
+ if (error = diskfs_start_translator (np, _diskfs_dotdot_file))
+ {
+ mutex_unlock (&np->lock);
+ return error;
+ }
+ control = np->translator.control;
+ }
+
+ mach_port_mod_refs (mach_task_self (), control, MACH_PORT_RIGHT_SEND, 1);
+ mutex_unlock (&np->lock);
+ error = fsys_getroot (childcontrol, cred->uids, cred->nuids,
+ cred->gids, cred->ngids, flags, retry,
+ retryname, retrypt);
+ if (error == MACH_SEND_INVALID_DEST)
+ {
+ mutex_lock (&np->lock);
+ if (np->translator.control == control)
+ fshelp_translator_drop (&np->translator);
+ mach_port_deallocate (mach_task_self (), control);
+ error = 0;
+ goto repeat_transcheck;
+ }
+
+ if (!error && *retrypt != MACH_PORT_NULL)
+ *retrypttype = MACH_MSG_TYPE_MOVE_SEND;
+ else
+ *retrypttype = MACH_MSG_TYPE_COPY_SEND;
+
+ return error;
+ }
+
+ /* Ignore O_NOTRANS here. */
+ if (type == S_IFLNK && !(flags & O_NOLINK))
+
+