[PATCH] New VFS Module "unityed_media" for sharing AVID projects

Jeremy Allison jra at samba.org
Mon Jan 5 15:35:30 MST 2015


On Tue, Dec 30, 2014 at 11:06:24AM +0100, Ralph Böhme wrote:
> On Fri, Dec 19, 2014 at 10:01:42PM +0100, Ralph Böhme wrote:
> > Hi Jeremy,
> > 
> > On Tue, Dec 16, 2014 at 03:20:07PM -0800, Jeremy Allison wrote:
> > > On Mon, Dec 08, 2014 at 06:55:35PM +0100, Ralph Böhme wrote:
> > > > Hi all,
> > > > 
> > > > attached is a new VFS module for improved AVID project sharing, from
> > > > the commit message:
> > > > It's been tested by 3rd party and reported to work flawlessly. Please
> > > > review, comment and/or push if ok.
> > > 
> > > First comment/fix needed.
> > > 
> > > get_digit_group() walks through a pathname using:
> > > 
> > > +       while (*p) {
> > > +               if (isdigit(*p)) {
> > > +                       *digit = (uintmax_t)strtoul(p, &endp, 10);
> > > +                       DEBUG(10, ("num_suffix = '%ju'\n",
> > > +                                             *digit));
> > > +                       return true;
> > > +               }
> > > +               p++;
> > > +       }
> > > 
> > > This won't work for non-ASCII files. Use next_codepoint()
> > > to walk through pathname strings.
> > 
> > thanks, will fix and resubmit.
> 
> updated patch attached.

Looks much better, but there's still some cruft
in the pathname processing probably left over
from the original code implementation.

For example: is_in_media_dir() it looks for
"./" and "../" - these are stripped out in
source3/smbd/reply.c:check_path_syntax_internal()
(and have been for may years :-).

Ralph, do you want to fix these up before commit
or do you want to do it later.

If you've already got it working and tested, I don't want
to delay adding the functionality, but we really
should make new code a little more polished than
some of the old stuff we have :-).

Let me know what you'd like to do !

Cheers,

	Jeremy.


> -- 
> SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
> phone: +49-551-370000-0, fax: +49-551-370000-9
> AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
> http://www.sernet.de,mailto:kontakt@sernet.de

> From 54b2442d180f460c234a43231c8cb7e00e6f316c Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Wed, 22 Oct 2014 19:17:12 +0200
> Subject: [PATCH] vfs_unityed_media: VFS module for sharing AVID projects
> 
> Based on <https://code.google.com/p/vfs-unityed-media/>.
> 
> The existing VFS module media_harmony has some problems relative to Avid
> media sharing:
> 
> Avid looks at the modification time of the ingest directory. Since
> media_harmony has everyone using the same directory, users (or client
> systems) have to somehow create "fake" directories with special names
> and then media_harmony returns the mod time of those fake directories
> for the different clients rather than the actual mod time of the
> communal ingest directory.
> 
> To make matters worse, users then have to have a special utility or
> understand how to update the modtime on these specially named
> directories. Otherwise, their client system will never update the
> indexes to show new media.
> 
> To make it even worse than that, Avid creates new directories on the
> fly, so you can't just set this up statically at the beginning. Avid
> will silently create a new directory and your reindexing problems will
> start all over until you create new fake directories.
> 
> With unityed_media:
> 
> * there are no reindexes between clients
> 
> * clients don't need to know which directories have been created for
>   them, it's automatic.
> 
> * clients never have to reindex other systems directories.
> 
> * unityed_media let's each client have their own directories.
> 
> * unityed_media works much more like Avid's own ISIS servers work.
> 
> A module option controls which name is appended to client specific
> paths: the username, the hostname (will not work with OS X) or the
> client's IP.
> 
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
>  docs-xml/manpages/vfs_unityed_media.8.xml |  115 ++
>  docs-xml/wscript_build                    |    1 +
>  source3/modules/vfs_unityed_media.c       | 1953 +++++++++++++++++++++++++++++
>  source3/modules/wscript_build             |    9 +
>  source3/wscript                           |    2 +-
>  5 files changed, 2079 insertions(+), 1 deletion(-)
>  create mode 100644 docs-xml/manpages/vfs_unityed_media.8.xml
>  create mode 100644 source3/modules/vfs_unityed_media.c
> 
> diff --git a/docs-xml/manpages/vfs_unityed_media.8.xml b/docs-xml/manpages/vfs_unityed_media.8.xml
> new file mode 100644
> index 0000000..ed52cda
> --- /dev/null
> +++ b/docs-xml/manpages/vfs_unityed_media.8.xml
> @@ -0,0 +1,115 @@
> +<?xml version="1.0" encoding="iso-8859-1"?>
> +<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
> +<refentry id="vfs_media_harmony.8">
> +
> +<refmeta>
> +	<refentrytitle>vfs_unityed_media</refentrytitle>
> +	<manvolnum>8</manvolnum>
> +	<refmiscinfo class="source">Samba</refmiscinfo>
> +	<refmiscinfo class="manual">System Administration tools</refmiscinfo>
> +	<refmiscinfo class="version">4.2</refmiscinfo>
> +</refmeta>
> +
> +
> +<refnamediv>
> +	<refname>vfs_unityed_media</refname>
> +	<refpurpose>Allow multiple Avid clients to share a network drive.</refpurpose>
> +</refnamediv>
> +
> +<refsynopsisdiv>
> +	<cmdsynopsis>
> +		<command>vfs objects = unityed_media</command>
> +	</cmdsynopsis>
> +</refsynopsisdiv>
> +
> +<refsect1>
> +	<title>DESCRIPTION</title>
> +
> +	<para>This VFS module is part of the
> +	<citerefentry><refentrytitle>samba</refentrytitle>
> +	<manvolnum>7</manvolnum></citerefentry> suite.</para>
> +
> +	<para>Unityed Media is related with Media Harmony VFS, the
> +	main difference between Unityed Media and Media Harmony is
> +	that Unityed Media doesn't need manual refreshing of media
> +	directories. Unityed Media handles your media files in similar
> +	way as Unity, ISIS, EditShare or another dedicated solution
> +	does. Without client-side application and on hardware of your
> +	choice.</para>
> +
> +	<para>This module is stackable.</para>
> +</refsect1>
> +
> +<refsect1>
> +	<title>CONFIGURATION</title>
> +
> +	<para>If Mac and Windows Avid clients will be accessing the same
> +	folder, they should be given separate share definitions, with
> +	hidden Mac files vetoed on the Windows share.  See EXAMPLES.</para>
> +</refsect1>
> +
> +<refsect1>
> +	<title>OPTIONS</title>
> +
> +	<variablelist>
> +
> +	  <varlistentry>
> +	    <term>unityed_media:clientid = user | hostname | ip </term>
> +	    <listitem>
> +	      <para>Controls what client related identifier is
> +	      appended to user specific paths:</para>
> +
> +	      <itemizedlist>
> +		<listitem><para><command>user (default)</command> -
> +		use the username.  </para></listitem>
> +
> +		<listitem><para><command>hostname</command> - use the
> +		hostname. Note this will not work with OS X clients as
> +		these always send a generic string ("workstation") to
> +		the server..</para></listitem>
> +
> +		<listitem><para><command>ip</command> - use the
> +		client's IP address.  NOTE: this is untested and may
> +		not work at all.</para></listitem>
> +	      </itemizedlist>
> +
> +	    </listitem>
> +	  </varlistentry>
> +	</variablelist>
> +</refsect1>
> +
> +<refsect1>
> +	<title>EXAMPLES</title>
> +
> +	<para>Enable unityed_media for Mac and Windows clients:</para>
> +<programlisting>
> +        <smbconfsection name="[avid_mac]"/>
> +	<smbconfoption name="path">/avid</smbconfoption>
> +	<smbconfoption name="vfs objects">unityed_media</smbconfoption>
> +        <smbconfsection name="[avid_win]"/>
> +	<smbconfoption name="path">/avid</smbconfoption>
> +	<smbconfoption name="vfs objects">unityed_media</smbconfoption>
> +	<smbconfoption name="veto files">/.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/</smbconfoption>
> +	<smbconfoption name="delete veto files">yes</smbconfoption>
> +</programlisting>
> +
> +</refsect1>
> +
> +<refsect1>
> +	<title>VERSION</title>
> +
> +	<para>This man page is correct for version 4.2 of the Samba suite.
> +	</para>
> +</refsect1>
> +
> +<refsect1>
> +	<title>AUTHOR</title>
> +
> +	<para>The original Samba software and related utilities
> +	were created by Andrew Tridgell. Samba is now developed
> +	by the Samba Team as an Open Source project similar
> +	to the way the Linux kernel is developed.</para>
> +
> +</refsect1>
> +
> +</refentry>
> diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build
> index f7d0db8..3ddcdc2 100644
> --- a/docs-xml/wscript_build
> +++ b/docs-xml/wscript_build
> @@ -82,6 +82,7 @@ manpages='''
>           manpages/vfs_syncops.8
>           manpages/vfs_time_audit.8
>           manpages/vfs_tsmsm.8
> +         manpages/vfs_unityed_media.8
>           manpages/vfs_worm.8
>           manpages/vfs_xattr_tdb.8
>           manpages/vfstest.1
> diff --git a/source3/modules/vfs_unityed_media.c b/source3/modules/vfs_unityed_media.c
> new file mode 100644
> index 0000000..72c8964
> --- /dev/null
> +++ b/source3/modules/vfs_unityed_media.c
> @@ -0,0 +1,1953 @@
> +/*
> + * Samba VFS module supporting multiple AVID clients sharing media.
> + *
> + * Copyright (C) 2005  Philip de Nier <philipn at users.sourceforge.net>
> + * Copyright (C) 2012  Andrew Klaassen <clawsoon at yahoo.com>
> + * Copyright (C) 2013  Milos Lukacek
> + * Copyright (C) 2013  Ralph Boehme <slow at samba.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +
> +/*
> + * Unityed Media is a Samba VFS module that allows multiple AVID
> + * clients to share media.
> + *
> + * Add this module to the vfs objects option in your Samba share
> + * configuration.
> + * eg.
> + *
> + *   [avid_win]
> + *	path = /video
> + *	vfs objects = unityed_media
> + *	...
> + *
> + * It is recommended that you separate out Samba shares for Mac
> + * and Windows clients, and add the following options to the shares
> + * for Windows clients	(NOTE: replace @ with *):
> + *
> + *	veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
> + *	delete veto files = yes
> + *
> + * This prevents hidden files from Mac clients interfering with Windows
> + * clients. If you find any more problem hidden files then add them to
> + * the list.
> + *
> + * Notes:
> + * This module is designed to work with AVID editing applications that
> + * look in the Avid MediaFiles or OMFI MediaFiles directory for media.
> + * It is not designed to work as expected in all circumstances for
> + * general use.
> + */
> +
> +
> +#include "includes.h"
> +#include "system/filesys.h"
> +#include "smbd/smbd.h"
> +#include "../smbd/globals.h"
> +#include "auth.h"
> +#include "../lib/tsocket/tsocket.h"
> +#include <libgen.h>
> +
> +#define UM_PARAM_TYPE_NAME "unityed_media"
> +
> +static const char *AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
> +static const size_t AVID_MXF_DIRNAME_LEN = 19;
> +static const char *OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
> +static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
> +static const char *APPLE_DOUBLE_PREFIX = "._";
> +static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
> +static int vfs_um_debug_level = DBGC_VFS;
> +
> +enum um_clientid {UM_CLIENTID_NAME, UM_CLIENTID_IP, UM_CLIENTID_HOSTNAME};
> +
> +struct um_config_data {
> +	enum um_clientid clientid;
> +};
> +
> +static const struct enum_list um_clientid[] = {
> +	{UM_CLIENTID_NAME, "user"},
> +	{UM_CLIENTID_IP, "ip"},
> +	{UM_CLIENTID_HOSTNAME, "hostname"},
> +	{-1, NULL}
> +};
> +
> +/* supplements the directory list stream */
> +typedef struct um_dirinfo_struct {
> +	DIR* dirstream;
> +	char *dirpath;
> +	char *clientPath;
> +	bool isInMediaFiles;
> +	char *clientSubDirname;
> +} um_dirinfo_struct;
> +
> +/**
> + * Returns true and first group of digits in path, false and 0 otherwise
> + **/
> +static bool get_digit_group(const char *path, uintmax_t *digit)
> +{
> +	const char *p = path;
> +	char *endp = NULL;
> +	codepoint_t cp;
> +	size_t size;
> +
> +	DEBUG(10, ("get_digit_group entering with path '%s'\n",
> +		   path));
> +
> +	/*
> +	 * Delibiretly initialize to 0 because callers use this result
> +	 * even though the string doesn't contain any number and we
> +	 * returned false
> +	 */
> +	*digit = 0;
> +
> +	while (*p) {
> +		cp = next_codepoint(p, &size);
> +		if (cp == -1) {
> +			return false;
> +		}
> +		if ((size == 1) && (isdigit(cp))) {
> +			*digit = (uintmax_t)strtoul(p, &endp, 10);
> +			DEBUG(10, ("num_suffix = '%ju'\n",
> +				   *digit));
> +			return true;
> +		}
> +		p += size;
> +	}
> +
> +	return false;
> +}
> +
> +/* Add "_<remote_name>.<number>" suffix to path or filename.
> + *
> + * Success: return 0
> + * Failure: set errno, path NULL, return -1
> + */
> +
> +static int alloc_append_client_suffix(vfs_handle_struct *handle,
> +				      char **path)
> +{
> +	int status = 0;
> +	uintmax_t number;
> +	const char *clientid;
> +	struct um_config_data *config;
> +
> +	DEBUG(10, ("Entering with path '%s'\n", *path));
> +
> +	SMB_VFS_HANDLE_GET_DATA(handle, config,
> +				struct um_config_data,
> +				return -1);
> +
> +	(void)get_digit_group(*path, &number);
> +
> +	switch (config->clientid) {
> +
> +	case UM_CLIENTID_IP:
> +		clientid = tsocket_address_inet_addr_string(
> +			handle->conn->sconn->remote_address, talloc_tos());
> +		if (clientid == NULL) {
> +			errno = ENOMEM;
> +			status = -1;
> +			goto err;
> +		}
> +		break;
> +
> +	case UM_CLIENTID_HOSTNAME:
> +		clientid = get_remote_machine_name();
> +		break;
> +
> +	case UM_CLIENTID_NAME:
> +	default:
> +		clientid = get_current_username();
> +		break;
> +	}
> +
> +	*path = talloc_asprintf_append(*path, "_%s.%ju",
> +				       clientid, number);
> +	if (*path == NULL) {
> +		DEBUG(1, ("alloc_append_client_suffix "
> +				     "out of memory\n"));
> +		errno = ENOMEM;
> +		status = -1;
> +		goto err;
> +	}
> +	DEBUG(10, ("Leaving with *path '%s'\n", *path));
> +err:
> +	return status;
> +}
> +
> +/* Returns true if the file or directory begins with the appledouble
> + * prefix.
> + */
> +static bool is_apple_double(const char* fname)
> +{
> +	bool ret = false;
> +
> +	DEBUG(10, ("Entering with fname '%s'\n", fname));
> +
> +	if (strnequal(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)) {
> +		ret = true;
> +	}
> +	DEBUG(10, ("Leaving with ret '%s'\n",
> +			      ret == true ? "true" : "false"));
> +	return ret;
> +}
> +
> +static bool starts_with_media_dir(const char* media_dirname,
> +				  size_t media_dirname_len,
> +				  const char *path)
> +{
> +	bool ret = false;
> +	const char *path_start = path;
> +
> +	DEBUG(10, ("Entering with media_dirname '%s' "
> +			      "path '%s'\n", media_dirname, path));
> +
> +	/* Sometimes Samba gives us "./OMFI MediaFiles". */
> +	if (strnequal(path, "./", 2)) {
> +		path_start += 2;
> +	}
> +
> +	if (strnequal(media_dirname, path_start, media_dirname_len)
> +	    &&
> +	    ((path_start[media_dirname_len] == '\0') ||
> +	     (path_start[media_dirname_len] == '/'))) {
> +		ret = true;
> +	}
> +
> +	DEBUG(10, ("Leaving with ret '%s'\n",
> +			      ret == true ? "true" : "false"));
> +	return ret;
> +}
> +
> +/*
> + * Returns true if the file or directory referenced by the path is ONE
> + * LEVEL below the AVID_MXF_DIRNAME or OMFI_MEDIAFILES_DIRNAME
> + * directory
> + */
> +static bool is_in_media_dir(const char *path)
> +{
> +	int transition_count = 0;
> +	const char *path_start = path;
> +	const char *p;
> +	const char *media_dirname;
> +	size_t media_dirname_len;
> +
> +	DEBUG(10, ("Entering with path'%s' ", path));
> +
> +	/* Sometimes Samba gives us "./OMFI MediaFiles". */
> +	if (strnequal(path, "./", 2)) {
> +		path_start += 2;
> +	}
> +
> +	if (strnequal(path_start, AVID_MXF_DIRNAME, AVID_MXF_DIRNAME_LEN)) {
> +		media_dirname = AVID_MXF_DIRNAME;
> +		media_dirname_len = AVID_MXF_DIRNAME_LEN;
> +	} else if (strnequal(path_start,
> +			     OMFI_MEDIAFILES_DIRNAME,
> +			     OMFI_MEDIAFILES_DIRNAME_LEN)) {
> +		media_dirname = OMFI_MEDIAFILES_DIRNAME;
> +		media_dirname_len = OMFI_MEDIAFILES_DIRNAME_LEN;
> +	} else {
> +		return false;
> +	}
> +
> +	if (path_start[media_dirname_len] == '\0') {
> +		goto out;
> +	}
> +
> +	p = path_start + media_dirname_len + 1;
> +
> +	while (true) {
> +		if (*p == '\0' || *p == '/') {
> +			if (strnequal(p - 3, "/..", 3)) {
> +				transition_count--;
> +			} else if ((p[-1] != '/') || !strnequal(p - 2, "/.", 2)) {
> +				transition_count++;
> +			}
> +		}
> +		if (*p == '\0') {
> +			break;
> +		}
> +		p++;
> +	}
> +
> +out:
> +	DEBUG(10, ("Going out with transition_count '%i'\n",
> +			      transition_count));
> +	if (((transition_count == 1) && (media_dirname == AVID_MXF_DIRNAME))
> +	    ||
> +	    ((transition_count == 0) && (media_dirname == OMFI_MEDIAFILES_DIRNAME))) {
> +		return true;
> +	}
> +	else return false;
> +}
> +
> +/*
> + * Returns true if the file or directory referenced by the path is
> + * below the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME
> + * directory The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME
> + * are assumed to be in the root directory, which is generally a safe
> + * assumption in the fixed-path world of Avid.
> + */
> +static bool is_in_media_files(const char *path)
> +{
> +	bool ret = false;
> +
> +	DEBUG(10, ("Entering with path '%s'\n", path));
> +
> +	if (starts_with_media_dir(AVID_MXF_DIRNAME,
> +				  AVID_MXF_DIRNAME_LEN, path) ||
> +	    starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
> +				  OMFI_MEDIAFILES_DIRNAME_LEN, path)) {
> +		ret = true;
> +	}
> +	DEBUG(10, ("Leaving with ret '%s'\n",
> +			      ret == true ? "true" : "false"));
> +	return ret;
> +}
> +
> +
> +/* Add client suffix to "pure-number" path.
> + *
> + * Caller must free newPath.
> + *
> + * Success: return 0
> + * Failure: set errno, newPath NULL, return -1
> + */
> +static int alloc_get_client_path(vfs_handle_struct *handle,
> +				 TALLOC_CTX *ctx,
> +				 const char *path_in,
> +				 char **path_out)
> +{
> +	int status = 0;
> +	char *p;
> +	char *digits;
> +	size_t digits_len;
> +	uintmax_t number;
> +
> +	*path_out = talloc_strdup(ctx, path_in);
> +        if (*path_out == NULL) {
> +		DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
> +		return -1;
> +	}
> +
> +	(void)get_digit_group(*path_out, &number);
> +
> +	digits = talloc_asprintf(NULL, "%ju", number);
> +        if (digits == NULL) {
> +		DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
> +		return -1;
> +	}
> +	digits_len = strlen(digits);
> +
> +	p = strstr(path_in, digits);
> +	if ((p)
> +	    &&
> +	    ((p[digits_len] == '\0') || (p[digits_len] == '/'))
> +	    &&
> +	    (((p - path_in > 0) && (p[-1] == '/'))
> +	     ||
> +	     (((p - path_in) > APPLE_DOUBLE_PREFIX_LEN)
> +	      &&
> +	      is_apple_double(p - APPLE_DOUBLE_PREFIX_LEN)
> +	      &&
> +	      (p[-(APPLE_DOUBLE_PREFIX_LEN + 1)] == '/'))))
> +	{
> +		(*path_out)[p - path_in + digits_len] = '\0';
> +
> +		status = alloc_append_client_suffix(handle, path_out);
> +		if (status != 0) {
> +			goto out;
> +		}
> +
> +                *path_out = talloc_strdup_append(*path_out, p + digits_len);
> +		if (*path_out == NULL) {
> +			DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
> +			status = -1;
> +			goto out;
> +		}
> +	}
> +out:
> +	/* path_out must be freed in caller. */
> +	DEBUG(10, ("Result:'%s'\n", *path_out));
> +	return status;
> +}
> +
> +/*
> + * Success: return 0
> + * Failure: set errno, return -1
> + */
> +static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
> +				      TALLOC_CTX *ctx,
> +				      const struct smb_filename *smb_fname,
> +				      struct smb_filename **client_fname)
> +{
> +	int status ;
> +
> +	DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
> +		   smb_fname->base_name));
> +
> +	*client_fname = cp_smb_filename(ctx, smb_fname);
> +	if (*client_fname == NULL) {
> +		DEBUG(1, ("cp_smb_filename returned NULL\n"));
> +		return -1;
> +	}
> +	status = alloc_get_client_path(handle, ctx,
> +				       smb_fname->base_name,
> +				       &(*client_fname)->base_name);
> +	if (status != 0) {
> +		return -1;
> +	}
> +
> +	DEBUG(10, ("Leaving with (*client_fname)->base_name "
> +		   "'%s'\n", (*client_fname)->base_name));
> +
> +	return 0;
> +}
> +
> +
> +/*
> + * Success: return 0
> + * Failure: set errno, return -1
> + */
> +static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
> +					 TALLOC_CTX *ctx,
> +					 char **path,
> +					 const char *suffix_number)
> +{
> +	int status;
> +
> +	DEBUG(10, ("Entering with suffix_number '%s'\n",
> +		   suffix_number));
> +
> +	*path = talloc_strdup(ctx, suffix_number);
> +	if (*path == NULL) {
> +		DEBUG(1, ("alloc_set_client_dirinfo_path ENOMEM\n"));
> +		return -1;
> +	}
> +	status = alloc_append_client_suffix(handle, path);
> +	if (status != 0) {
> +		return -1;
> +	}
> +
> +	DEBUG(10, ("Leaving with *path '%s'\n", *path));
> +
> +	return 0;
> +}
> +
> +static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
> +				    const char *fname,
> +				    struct um_dirinfo_struct **di_result)
> +{
> +	int status = 0;
> +	char *digits;
> +	uintmax_t number;
> +	struct um_dirinfo_struct *dip;
> +
> +	DEBUG(10, ("Entering with fname '%s'\n", fname));
> +
> +	*di_result = talloc(NULL, struct um_dirinfo_struct);
> +	if (*di_result == NULL) {
> +		goto err;
> +	}
> +	dip = *di_result;
> +
> +	dip->dirpath = talloc_strdup(dip, fname);
> +	if (dip->dirpath == NULL) {
> +		goto err;
> +	}
> +
> +	if (!is_in_media_files(fname)) {
> +		dip->isInMediaFiles = false;
> +		dip->clientPath = NULL;
> +		dip->clientSubDirname = NULL;
> +		goto out;
> +	}
> +
> +	dip->isInMediaFiles = true;
> +
> +	(void)get_digit_group(fname, &number);
> +	digits = talloc_asprintf(talloc_tos(), "%ju", number);
> +	if (digits == NULL) {
> +		goto err;
> +	}
> +
> +	status = alloc_set_client_dirinfo_path(handle, dip,
> +					       &dip->clientSubDirname,
> +					       digits);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = alloc_get_client_path(handle, dip, fname,
> +				       &dip->clientPath);
> +	if (status != 0 || dip->clientPath == NULL) {
> +		goto err;
> +	}
> +
> +out:
> +	DEBUG(10, ("Leaving with (*dirInfo)->dirpath '%s', "
> +			      "(*dirInfo)->clientPath '%s'\n",
> +			      dip->dirpath, dip->clientPath));
> +	return status;
> +
> +err:
> +	DEBUG(1, ("Failing with fname '%s'\n", fname));
> +	TALLOC_FREE(*di_result);
> +	status = -1;
> +	errno = ENOMEM;
> +	return status;
> +}
> +
> +/**********************************************************************
> + * VFS functions
> + **********************************************************************/
> +
> +/*
> + * Success: return 0
> + * Failure: set errno, return -1
> + */
> +static int um_statvfs(struct vfs_handle_struct *handle,
> +		      const char *path,
> +		      struct vfs_statvfs_struct *statbuf)
> +{
> +	int status;
> +	char *clientPath = NULL;
> +
> +	DEBUG(10, ("Entering with path '%s'\n", path));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &clientPath);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
> +err:
> +	TALLOC_FREE(clientPath);
> +	DEBUG(10, ("Leaving with path '%s'\n", path));
> +	return status;
> +}
> +
> +/* Success: return a um_dirinfo_struct cast as a DIR
> + * Failure: set errno, return NULL
> + */
> +static DIR *um_opendir(vfs_handle_struct *handle,
> +		       const char *fname,
> +		       const char *mask,
> +		       uint32 attr)
> +{
> +	struct um_dirinfo_struct *dirInfo;
> +
> +	DEBUG(10, ("Entering with fname '%s'\n", fname));
> +
> +	if (alloc_set_client_dirinfo(handle, fname, &dirInfo)) {
> +		goto err;
> +	}
> +
> +	if (!dirInfo->isInMediaFiles) {
> +		dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
> +			handle, fname, mask, attr);
> +	} else {
> +		dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
> +			handle, dirInfo->clientPath, mask, attr);
> +	}
> +
> +	if (dirInfo->dirstream == NULL) {
> +		goto err;
> +	}
> +
> +	DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
> +			      "dirInfo->clientPath '%s'\n",
> +			      dirInfo->dirpath,
> +			      dirInfo->clientPath));
> +	return (DIR*)dirInfo;
> +
> +err:
> +	DEBUG(1, ("Failing with fname '%s'\n", fname));
> +	TALLOC_FREE(dirInfo);
> +	return NULL;
> +}
> +
> +static DIR *um_fdopendir(vfs_handle_struct *handle,
> +			 files_struct *fsp,
> +			 const char *mask,
> +			 uint32 attr)
> +{
> +	struct um_dirinfo_struct *dirInfo = NULL;
> +	DIR *dirstream;
> +
> +	DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
> +		   fsp->fsp_name->base_name));
> +
> +	dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
> +	if (!dirstream) {
> +		goto err;
> +	}
> +
> +	if (alloc_set_client_dirinfo(handle,
> +				     fsp->fsp_name->base_name,
> +				     &dirInfo)) {
> +		goto err;
> +	}
> +
> +	dirInfo->dirstream = dirstream;
> +
> +	if (!dirInfo->isInMediaFiles) {
> +		/*
> +		 * FIXME: this is the original code, something must be
> +		 * missing here, but what? -slow
> +		 */
> +		goto out;
> +	}
> +
> +out:
> +	DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
> +		   "dirInfo->clientPath '%s', "
> +		   "fsp->fsp_name->st.st_ex_mtime %s",
> +		   dirInfo->dirpath,
> +		   dirInfo->clientPath,
> +		   ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
> +	return (DIR *) dirInfo;
> +
> +err:
> +	DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
> +		  fsp->fsp_name->base_name));
> +	TALLOC_FREE(dirInfo);
> +	return NULL;
> +}
> +
> +/*
> + * skip own suffixed directory
> + * replace own suffixed directory with non suffixed.
> + *
> + * Success: return dirent
> + * End of data: return NULL
> + * Failure: set errno, return NULL
> + */
> +static struct dirent *um_readdir(vfs_handle_struct *handle,
> +				 DIR *dirp,
> +				 SMB_STRUCT_STAT *sbuf)
> +{
> +	um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
> +	struct dirent *d = NULL;
> +	int skip;
> +
> +	DEBUG(10, ("dirInfo->dirpath '%s', "
> +		   "dirInfo->clientPath '%s', "
> +		   "dirInfo->isInMediaFiles '%s', "
> +		   "dirInfo->clientSubDirname '%s'\n",
> +		   dirInfo->dirpath,
> +		   dirInfo->clientPath,
> +		   dirInfo->isInMediaFiles ? "true" : "false",
> +		   dirInfo->clientSubDirname));
> +
> +	if (!dirInfo->isInMediaFiles) {
> +		return SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
> +	}
> +
> +	do {
> +		const char* dname;
> +		bool isAppleDouble;
> +		char *digits;
> +		size_t digits_len;
> +		uintmax_t number;
> +
> +		skip = false;
> +		d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
> +
> +		if (d == NULL) {
> +			break;
> +		}
> +
> +		/* ignore apple double prefix for logic below */
> +		if (is_apple_double(d->d_name)) {
> +			dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
> +			isAppleDouble = true;
> +		} else {
> +			dname = d->d_name;
> +			isAppleDouble = false;
> +		}
> +
> +		DEBUG(10, ("dname = '%s'\n", dname));
> +
> +		(void)get_digit_group(dname, &number);
> +		digits = talloc_asprintf(talloc_tos(), "%ju", number);
> +		if (digits == NULL) {
> +			DEBUG(1, ("out of memory"));
> +			goto err;
> +		}
> +		digits_len = strlen(digits);
> +
> +		if (alloc_set_client_dirinfo_path(handle,
> +						  dirInfo,
> +						  &((dirInfo)->clientSubDirname),
> +						  digits)) {
> +			goto err;
> +		}
> +
> +		/*
> +		 * If set to "true", vfs shows digits-only
> +		 * non-suffixed subdirectories.  Normally, such
> +		 * subdirectories can exists only in non-media
> +		 * directories, so we set it to "false".  Otherwise,
> +		 * if we have such subdirectories (probably created
> +		 * over not "unityed" connection), it can be little
> +		 * bit confusing.
> +		 */
> +		if (strequal(dname, digits)) {
> +			skip = false;
> +		} else if (strequal(dname, dirInfo->clientSubDirname)) {
> +			/*
> +			 * Remove suffix of this client's suffixed
> +			 * subdirectories
> +			 */
> +			if (isAppleDouble) {
> +				d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
> +			} else {
> +				d->d_name[digits_len] = '\0';
> +			}
> +		} else if (strnequal(digits, dname, digits_len)) {
> +			/*
> +			 * Set to false to see another clients subdirectories
> +			 */
> +			skip = false;
> +		}
> +	} while (skip);
> +
> +	DEBUG(10, ("Leaving um_readdir\n"));
> +	return d;
> +err:
> +	TALLOC_FREE(dirInfo);
> +	return NULL;
> +}
> +
> +static void um_seekdir(vfs_handle_struct *handle,
> +		       DIR *dirp,
> +		       long offset)
> +{
> +	DEBUG(10, ("Entering and leaving um_seekdir\n"));
> +	SMB_VFS_NEXT_SEEKDIR(handle,
> +			     ((um_dirinfo_struct*)dirp)->dirstream, offset);
> +}
> +
> +static long um_telldir(vfs_handle_struct *handle,
> +		       DIR *dirp)
> +{
> +	DEBUG(10, ("Entering and leaving um_telldir\n"));
> +	return SMB_VFS_NEXT_TELLDIR(handle,
> +				    ((um_dirinfo_struct*)dirp)->dirstream);
> +}
> +
> +static void um_rewinddir(vfs_handle_struct *handle,
> +			 DIR *dirp)
> +{
> +	DEBUG(10, ("Entering and leaving um_rewinddir\n"));
> +	SMB_VFS_NEXT_REWINDDIR(handle,
> +			       ((um_dirinfo_struct*)dirp)->dirstream);
> +}
> +
> +static int um_mkdir(vfs_handle_struct *handle,
> +		    const char *path,
> +		    mode_t mode)
> +{
> +	int status;
> +	char *clientPath;
> +	TALLOC_CTX *ctx;
> +
> +
> +	DEBUG(10, ("Entering with path '%s'\n", path));
> +
> +	if (!is_in_media_files(path) || !is_in_media_dir(path)) {
> +		return SMB_VFS_NEXT_MKDIR(handle, path, mode);
> +	}
> +
> +	clientPath = NULL;
> +	ctx = talloc_tos();
> +
> +	if ((status = alloc_get_client_path(handle, ctx,
> +					    path,
> +					    &clientPath))) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_MKDIR(handle, clientPath, mode);
> +err:
> +	TALLOC_FREE(clientPath);
> +	DEBUG(10, ("Leaving with path '%s'\n", path));
> +	return status;
> +}
> +
> +static int um_rmdir(vfs_handle_struct *handle,
> +		    const char *path)
> +{
> +	int status;
> +	char *clientPath;
> +	TALLOC_CTX *ctx;
> +
> +
> +	DEBUG(10, ("Entering with path '%s'\n", path));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_RMDIR(handle, path);
> +	}
> +
> +	clientPath = NULL;
> +	ctx = talloc_tos();
> +
> +	if ((status = alloc_get_client_path(handle, ctx,
> +					    path,
> +					    &clientPath))) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_RMDIR(handle, clientPath);
> +err:
> +	TALLOC_FREE(clientPath);
> +	DEBUG(10, ("Leaving with path '%s'\n", path));
> +	return status;
> +}
> +
> +static int um_closedir(vfs_handle_struct *handle,
> +		       DIR *dirp)
> +{
> +	DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
> +
> +	TALLOC_FREE(dirp);
> +
> +	return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
> +}
> +
> +static void um_init_search_op(vfs_handle_struct *handle,
> +			      DIR *dirp)
> +{
> +	DEBUG(10, ("Entering and leaving um_init_search_op\n"));
> +
> +	SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
> +				    ((um_dirinfo_struct*)dirp)->dirstream);
> +}
> +
> +static int um_open(vfs_handle_struct *handle,
> +		   struct smb_filename *smb_fname,
> +		   files_struct *fsp,
> +		   int flags,
> +		   mode_t mode)
> +{
> +	int ret;
> +	struct smb_filename *client_fname = NULL;
> +
> +	DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
> +			      smb_fname->base_name));
> +
> +	if (!is_in_media_files(smb_fname->base_name)) {
> +		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
> +	}
> +
> +	if (alloc_get_client_smb_fname(handle, talloc_tos(),
> +				       smb_fname,
> +				       &client_fname)) {
> +		ret = -1;
> +		goto err;
> +	}
> +
> +	/*
> +	 * FIXME:
> +	 * What about fsp->fsp_name?  We also have to get correct stat
> +	 * info into fsp and smb_fname for DB files, don't we?
> +	 */
> +
> +	DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
> +		   "smb_fname->st.st_ex_mtime %s"
> +		   "fsp->fsp_name->st.st_ex_mtime %s",
> +			      smb_fname->base_name,
> +			      ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
> +			      ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
> +
> +	ret = SMB_VFS_NEXT_OPEN(handle, client_fname, fsp, flags, mode);
> +err:
> +	TALLOC_FREE(client_fname);
> +	DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
> +			      smb_fname->base_name));
> +	return ret;
> +}
> +
> +static NTSTATUS um_create_file(vfs_handle_struct *handle,
> +			       struct smb_request *req,
> +			       uint16_t root_dir_fid,
> +			       struct smb_filename *smb_fname,
> +			       uint32_t access_mask,
> +			       uint32_t share_access,
> +			       uint32_t create_disposition,
> +			       uint32_t create_options,
> +			       uint32_t file_attributes,
> +			       uint32_t oplock_request,
> +			       struct smb2_lease *lease,
> +			       uint64_t allocation_size,
> +			       uint32_t private_flags,
> +			       struct security_descriptor *sd,
> +			       struct ea_list *ea_list,
> +			       files_struct **result_fsp,
> +			       int *pinfo,
> +			       const struct smb2_create_blobs *in_context_blobs,
> +			       struct smb2_create_blobs *out_context_blobs)
> +{
> +	NTSTATUS status;
> +	struct smb_filename *client_fname = NULL;
> +
> +	DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
> +		   smb_fname->base_name));
> +
> +	if (!is_in_media_files(smb_fname->base_name)) {
> +		return SMB_VFS_NEXT_CREATE_FILE(
> +			handle,
> +			req,
> +			root_dir_fid,
> +			smb_fname,
> +			access_mask,
> +			share_access,
> +			create_disposition,
> +			create_options,
> +			file_attributes,
> +			oplock_request,
> +			lease,
> +			allocation_size,
> +			private_flags,
> +			sd,
> +			ea_list,
> +			result_fsp,
> +			pinfo,
> +			in_context_blobs,
> +			out_context_blobs);
> +	}
> +
> +	if (alloc_get_client_smb_fname(handle, talloc_tos(),
> +				       smb_fname,
> +				       &client_fname)) {
> +		status = map_nt_error_from_unix(errno);
> +		goto err;
> +	}
> +
> +	/*
> +	 * FIXME:
> +	 * This only creates files, so we don't have to worry about
> +	 * our fake directory stat'ing here.  But we still need to
> +	 * route stat calls for DB files properly, right?
> +	 */
> +	status = SMB_VFS_NEXT_CREATE_FILE(
> +		handle,
> +		req,
> +		root_dir_fid,
> +		client_fname,
> +		access_mask,
> +		share_access,
> +		create_disposition,
> +		create_options,
> +		file_attributes,
> +		oplock_request,
> +		lease,
> +		allocation_size,
> +		private_flags,
> +		sd,
> +		ea_list,
> +		result_fsp,
> +		pinfo,
> +		in_context_blobs,
> +		out_context_blobs);
> +err:
> +	TALLOC_FREE(client_fname);
> +	DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
> +		   "smb_fname->st.st_ex_mtime %s"
> +		   " fsp->fsp_name->st.st_ex_mtime %s",
> +		   smb_fname->base_name,
> +		   ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
> +		   (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
> +		   ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
> +		   "No fsp time\n"));
> +	return status;
> +}
> +
> +static int um_rename(vfs_handle_struct *handle,
> +		     const struct smb_filename *smb_fname_src,
> +		     const struct smb_filename *smb_fname_dst)
> +{
> +	int status;
> +	struct smb_filename *src_client_fname = NULL;
> +	struct smb_filename *dst_client_fname = NULL;
> +
> +	DEBUG(10, ("Entering with "
> +		   "smb_fname_src->base_name '%s', "
> +		   "smb_fname_dst->base_name '%s'\n",
> +		   smb_fname_src->base_name,
> +		   smb_fname_dst->base_name));
> +
> +	if (!is_in_media_files(smb_fname_src->base_name)
> +	    &&
> +	    !is_in_media_files(smb_fname_dst->base_name)) {
> +		return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
> +					   smb_fname_dst);
> +	}
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    smb_fname_src,
> +					    &src_client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    smb_fname_dst,
> +					    &dst_client_fname);
> +
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_RENAME(handle, src_client_fname,
> +				     dst_client_fname);
> +err:
> +	TALLOC_FREE(dst_client_fname);
> +	TALLOC_FREE(src_client_fname);
> +	DEBUG(10, ("Leaving with smb_fname_src->base_name '%s',"
> +		   " smb_fname_dst->base_name '%s'\n",
> +		   smb_fname_src->base_name,
> +		   smb_fname_dst->base_name));
> +	return status;
> +}
> +
> +/*
> + * Success: return 0
> + * Failure: set errno, return -1
> + */
> +static int um_stat(vfs_handle_struct *handle,
> +		   struct smb_filename *smb_fname)
> +{
> +	int status = 0;
> +	struct smb_filename *client_fname = NULL;
> +
> +	DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
> +		   smb_fname->base_name));
> +
> +	if (!is_in_media_files(smb_fname->base_name)) {
> +		return SMB_VFS_NEXT_STAT(handle, smb_fname);
> +	}
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    smb_fname,
> +					    &client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +	DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
> +		   client_fname->base_name));
> +
> +	status = SMB_VFS_NEXT_STAT(handle, client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	/*
> +	 * Unlike functions with const smb_filename, we have to modify
> +	 * smb_fname itself to pass our info back up.
> +	 */
> +	DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
> +		   smb_fname->base_name, client_fname->base_name));
> +	smb_fname->st = client_fname->st;
> +
> +err:
> +	TALLOC_FREE(client_fname);
> +	DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
> +		   ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
> +	return status;
> +}
> +
> +static int um_lstat(vfs_handle_struct *handle,
> +		    struct smb_filename *smb_fname)
> +{
> +	int status = 0;
> +	struct smb_filename *client_fname = NULL;
> +
> +	DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
> +		   smb_fname->base_name));
> +
> +	if (!is_in_media_files(smb_fname->base_name)) {
> +		return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
> +	}
> +
> +	client_fname = NULL;
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    smb_fname,
> +					    &client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +	status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	smb_fname->st = client_fname->st;
> +
> +err:
> +	TALLOC_FREE(client_fname);
> +	DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
> +		   ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
> +	return status;
> +}
> +
> +static int um_fstat(vfs_handle_struct *handle,
> +		    files_struct *fsp, SMB_STRUCT_STAT *sbuf)
> +{
> +	int status = 0;
> +
> +	DEBUG(10, ("Entering with fsp->fsp_name->base_name "
> +		   "'%s'\n", fsp_str_dbg(fsp)));
> +
> +	status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
> +	if (status != 0) {
> +		goto out;
> +	}
> +
> +	if ((fsp->fsp_name == NULL) ||
> +	    !is_in_media_files(fsp->fsp_name->base_name)) {
> +		goto out;
> +	}
> +
> +	status = um_stat(handle, fsp->fsp_name);
> +	if (status != 0) {
> +		goto out;
> +	}
> +
> +	*sbuf = fsp->fsp_name->st;
> +
> +out:
> +	DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
> +		   fsp->fsp_name != NULL ?
> +		   ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
> +	return status;
> +}
> +
> +static int um_unlink(vfs_handle_struct *handle,
> +		     const struct smb_filename *smb_fname)
> +{
> +	int status;
> +	struct smb_filename *client_fname = NULL;
> +
> +	DEBUG(10, ("Entering um_unlink\n"));
> +
> +	if (!is_in_media_files(smb_fname->base_name)) {
> +		return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
> +	}
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    smb_fname,
> +					    &client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_UNLINK(handle, client_fname);
> +
> +err:
> +	TALLOC_FREE(client_fname);
> +	return status;
> +}
> +
> +static int um_chmod(vfs_handle_struct *handle,
> +		    const char *path,
> +		    mode_t mode)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_chmod\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_CHMOD(handle, path, mode);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_CHMOD(handle, client_path, mode);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_chown(vfs_handle_struct *handle,
> +		    const char *path,
> +		    uid_t uid,
> +		    gid_t gid)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_chown\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_CHOWN(handle, client_path, uid, gid);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_lchown(vfs_handle_struct *handle,
> +		     const char *path,
> +		     uid_t uid,
> +		     gid_t gid)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_lchown\n"));
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_LCHOWN(handle, client_path, uid, gid);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_chdir(vfs_handle_struct *handle,
> +		    const char *path)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_chdir\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_CHDIR(handle, path);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_CHDIR(handle, client_path);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_ntimes(vfs_handle_struct *handle,
> +		     const struct smb_filename *smb_fname,
> +		     struct smb_file_time *ft)
> +{
> +	int status;
> +	struct smb_filename *client_fname = NULL;
> +
> +	DEBUG(10, ("Entering um_ntimes\n"));
> +
> +	if (!is_in_media_files(smb_fname->base_name)) {
> +		return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
> +	}
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    smb_fname, &client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_NTIMES(handle, client_fname, ft);
> +
> +err:
> +	TALLOC_FREE(client_fname);
> +	return status;
> +}
> +
> +static int um_symlink(vfs_handle_struct *handle,
> +		      const char *oldpath,
> +		      const char *newpath)
> +{
> +	int status;
> +	char *old_client_path = NULL;
> +	char *new_client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_symlink\n"));
> +
> +	if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
> +		return SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       oldpath, &old_client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       newpath, &new_client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_SYMLINK(handle,
> +				      old_client_path,
> +				      new_client_path);
> +
> +err:
> +	TALLOC_FREE(new_client_path);
> +	TALLOC_FREE(old_client_path);
> +	return status;
> +}
> +
> +static int um_readlink(vfs_handle_struct *handle,
> +		       const char *path,
> +		       char *buf,
> +		       size_t bufsiz)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_readlink\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_READLINK(handle, client_path, buf, bufsiz);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_link(vfs_handle_struct *handle,
> +		   const char *oldpath,
> +		   const char *newpath)
> +{
> +	int status;
> +	char *old_client_path = NULL;
> +	char *new_client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_link\n"));
> +	if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
> +		return SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       oldpath, &old_client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       newpath, &new_client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_LINK(handle, old_client_path, new_client_path);
> +
> +err:
> +	TALLOC_FREE(new_client_path);
> +	TALLOC_FREE(old_client_path);
> +	return status;
> +}
> +
> +static int um_mknod(vfs_handle_struct *handle,
> +		    const char *pathname,
> +		    mode_t mode,
> +		    SMB_DEV_T dev)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_mknod\n"));
> +	if (!is_in_media_files(pathname)) {
> +		return SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       pathname, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_MKNOD(handle, client_path, mode, dev);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static char *um_realpath(vfs_handle_struct *handle,
> +			 const char *path)
> +{
> +	char *buf = NULL;
> +	char *client_path = NULL;
> +	int status;
> +
> +	DEBUG(10, ("Entering um_realpath\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_REALPATH(handle, path);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	buf = SMB_VFS_NEXT_REALPATH(handle, client_path);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return buf;
> +}
> +
> +static int um_chflags(vfs_handle_struct *handle,
> +		      const char *path,
> +		      unsigned int flags)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_chflags\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_CHFLAGS(handle, client_path, flags);
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static NTSTATUS um_streaminfo(struct vfs_handle_struct *handle,
> +			      struct files_struct *fsp,
> +			      const char *fname,
> +			      TALLOC_CTX *ctx,
> +			      unsigned int *num_streams,
> +			      struct stream_struct **streams)
> +{
> +	NTSTATUS status;
> +	char *client_path = NULL;
> +	int ret;
> +
> +	DEBUG(10, ("Entering um_streaminfo\n"));
> +
> +	if (!is_in_media_files(fname)) {
> +		return SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
> +					       ctx, num_streams, streams);
> +	}
> +
> +	ret = alloc_get_client_path(handle, talloc_tos(),
> +				    fname, &client_path);
> +	if (ret != 0) {
> +		status = map_nt_error_from_unix(errno);
> +		goto err;
> +	}
> +
> +	/*
> +	 * This only works on files, so we don't have to worry about
> +	 * our fake directory stat'ing here.  But what does this
> +	 * function do, exactly?  Does it need extra modifications for
> +	 * the Avid stuff?
> +	 */
> +	status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, client_path,
> +					 ctx, num_streams, streams);
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +/*
> + * Ignoring get_real_filename function because the default doesn't do
> + * anything.
> + */
> +
> +static NTSTATUS um_get_nt_acl(vfs_handle_struct *handle,
> +			      const char *name,
> +			      uint32 security_info,
> +			      TALLOC_CTX *mem_ctx,
> +			      struct security_descriptor **ppdesc)
> +{
> +	NTSTATUS status;
> +	char *client_path = NULL;
> +	int ret;
> +
> +	DEBUG(10, ("Entering um_get_nt_acl\n"));
> +
> +	if (!is_in_media_files(name)) {
> +		return SMB_VFS_NEXT_GET_NT_ACL(handle, name,
> +					       security_info,
> +					       mem_ctx, ppdesc);
> +	}
> +
> +	ret = alloc_get_client_path(handle, talloc_tos(),
> +				    name, &client_path);
> +	if (ret != 0) {
> +		status = map_nt_error_from_unix(errno);
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_path,
> +					 security_info,
> +					 mem_ctx, ppdesc);
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_chmod_acl(vfs_handle_struct *handle,
> +			const char *path,
> +			mode_t mode)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_chmod_acl\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_CHMOD_ACL(handle, client_path, mode);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static SMB_ACL_T um_sys_acl_get_file(vfs_handle_struct *handle,
> +				     const char *path_p,
> +				     SMB_ACL_TYPE_T type,
> +				     TALLOC_CTX *mem_ctx)
> +{
> +	SMB_ACL_T ret;
> +	char *client_path = NULL;
> +	int status;
> +
> +	DEBUG(10, ("Entering um_sys_acl_get_file\n"));
> +
> +	if (!is_in_media_files(path_p)) {
> +		return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p,
> +						     type, mem_ctx);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path_p, &client_path);
> +	if (status != 0) {
> +		ret = NULL;
> +		goto err;
> +	}
> +
> +	ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, client_path, type, mem_ctx);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return ret;
> +}
> +
> +static int um_sys_acl_set_file(vfs_handle_struct *handle,
> +			       const char *name,
> +			       SMB_ACL_TYPE_T acltype,
> +			       SMB_ACL_T theacl)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_sys_acl_set_file\n"));
> +
> +	if (!is_in_media_files(name)) {
> +		return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
> +						     acltype, theacl);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       name, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, client_path,
> +					       acltype, theacl);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_sys_acl_delete_def_file(vfs_handle_struct *handle,
> +				      const char *path)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_sys_acl_delete_def_file\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, path);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +					    path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, client_path);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static ssize_t um_getxattr(struct vfs_handle_struct *handle,
> +			   const char *path,
> +			   const char *name,
> +			   void *value,
> +			   size_t size)
> +{
> +	ssize_t ret;
> +	char *client_path = NULL;
> +	int status;
> +
> +	DEBUG(10, ("Entering um_getxattr\n"));
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_GETXATTR(handle, path, name, value, size);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		ret = -1;
> +		goto err;
> +	}
> +
> +	ret = SMB_VFS_NEXT_GETXATTR(handle, client_path, name, value, size);
> +err:
> +	TALLOC_FREE(client_path);
> +	return ret;
> +}
> +
> +static ssize_t um_listxattr(struct vfs_handle_struct *handle,
> +			    const char *path,
> +			    char *list,
> +			    size_t size)
> +{
> +	ssize_t ret;
> +	char *client_path = NULL;
> +	int status;
> +
> +	DEBUG(10, ("Entering um_listxattr\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		ret = -1;
> +		goto err;
> +	}
> +
> +	ret = SMB_VFS_NEXT_LISTXATTR(handle, client_path, list, size);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return ret;
> +}
> +
> +static int um_removexattr(struct vfs_handle_struct *handle,
> +			  const char *path,
> +			  const char *name)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_removexattr\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_REMOVEXATTR(handle, client_path, name);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static int um_setxattr(struct vfs_handle_struct *handle,
> +		       const char *path,
> +		       const char *name,
> +		       const void *value,
> +		       size_t size,
> +		       int flags)
> +{
> +	int status;
> +	char *client_path = NULL;
> +
> +	DEBUG(10, ("Entering um_setxattr\n"));
> +
> +	if (!is_in_media_files(path)) {
> +		return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
> +					     size, flags);
> +	}
> +
> +	status = alloc_get_client_path(handle, talloc_tos(),
> +				       path, &client_path);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_SETXATTR(handle, client_path, name, value,
> +				       size, flags);
> +
> +err:
> +	TALLOC_FREE(client_path);
> +	return status;
> +}
> +
> +static bool um_is_offline(struct vfs_handle_struct *handle,
> +			  const struct smb_filename *fname,
> +			  SMB_STRUCT_STAT *sbuf)
> +{
> +	bool ret;
> +	struct smb_filename *client_fname = NULL;
> +	int status;
> +
> +	DEBUG(10, ("Entering um_is_offline\n"));
> +
> +	if (!is_in_media_files(fname->base_name)) {
> +		return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
> +	}
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    fname, &client_fname);
> +	if (status != 0) {
> +		ret = false;
> +		goto err;
> +	}
> +
> +	ret = SMB_VFS_NEXT_IS_OFFLINE(handle, client_fname, sbuf);
> +
> +err:
> +	TALLOC_FREE(client_fname);
> +	return ret;
> +}
> +
> +static int um_set_offline(struct vfs_handle_struct *handle,
> +			  const struct smb_filename *fname)
> +{
> +	int status;
> +	struct smb_filename *client_fname = NULL;
> +
> +	DEBUG(10, ("Entering um_set_offline\n"));
> +
> +	if (!is_in_media_files(fname->base_name)) {
> +		return SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
> +	}
> +
> +	status = alloc_get_client_smb_fname(handle, talloc_tos(),
> +					    fname, &client_fname);
> +	if (status != 0) {
> +		goto err;
> +	}
> +
> +	status = SMB_VFS_NEXT_SET_OFFLINE(handle, client_fname);
> +
> +err:
> +	TALLOC_FREE(client_fname);
> +	return status;
> +}
> +
> +static int um_connect(vfs_handle_struct *handle,
> +			 const char *service,
> +			 const char *user)
> +{
> +	int rc;
> +	struct um_config_data *config;
> +	int enumval;
> +
> +	rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
> +	if (rc != 0) {
> +		return rc;
> +	}
> +
> +	config = talloc_zero(handle->conn, struct um_config_data);
> +	if (!config) {
> +		DEBUG(1, ("talloc_zero() failed\n"));
> +		errno = ENOMEM;
> +		return -1;
> +	}
> +
> +	enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
> +			       "clientid", um_clientid, UM_CLIENTID_NAME);
> +	if (enumval == -1) {
> +		DEBUG(1, ("value for %s: type unknown\n",
> +			  UM_PARAM_TYPE_NAME));
> +		return -1;
> +	}
> +	config->clientid = (enum um_clientid)enumval;
> +
> +	SMB_VFS_HANDLE_SET_DATA(handle, config,
> +				NULL, struct um_config_data,
> +				return -1);
> +
> +	return 0;
> +}
> +
> +/* VFS operations structure */
> +
> +static struct vfs_fn_pointers vfs_um_fns = {
> +	.connect_fn = um_connect,
> +
> +	/* Disk operations */
> +
> +	.statvfs_fn = um_statvfs,
> +
> +	/* Directory operations */
> +
> +	.opendir_fn = um_opendir,
> +	.fdopendir_fn = um_fdopendir,
> +	.readdir_fn = um_readdir,
> +	.seekdir_fn = um_seekdir,
> +	.telldir_fn = um_telldir,
> +	.rewind_dir_fn = um_rewinddir,
> +	.mkdir_fn = um_mkdir,
> +	.rmdir_fn = um_rmdir,
> +	.closedir_fn = um_closedir,
> +	.init_search_op_fn = um_init_search_op,
> +
> +	/* File operations */
> +
> +	.open_fn = um_open,
> +	.create_file_fn = um_create_file,
> +	.rename_fn = um_rename,
> +	.stat_fn = um_stat,
> +	.lstat_fn = um_lstat,
> +	.fstat_fn = um_fstat,
> +	.unlink_fn = um_unlink,
> +	.chmod_fn = um_chmod,
> +	.chown_fn = um_chown,
> +	.lchown_fn = um_lchown,
> +	.chdir_fn = um_chdir,
> +	.ntimes_fn = um_ntimes,
> +	.symlink_fn = um_symlink,
> +	.readlink_fn = um_readlink,
> +	.link_fn = um_link,
> +	.mknod_fn = um_mknod,
> +	.realpath_fn = um_realpath,
> +	.chflags_fn = um_chflags,
> +	.streaminfo_fn = um_streaminfo,
> +
> +	/* NT ACL operations. */
> +
> +	.get_nt_acl_fn = um_get_nt_acl,
> +
> +	/* POSIX ACL operations. */
> +
> +	.chmod_acl_fn = um_chmod_acl,
> +
> +	.sys_acl_get_file_fn = um_sys_acl_get_file,
> +	.sys_acl_set_file_fn = um_sys_acl_set_file,
> +	.sys_acl_delete_def_file_fn = um_sys_acl_delete_def_file,
> +
> +	/* EA operations. */
> +	.getxattr_fn = um_getxattr,
> +	.listxattr_fn = um_listxattr,
> +	.removexattr_fn = um_removexattr,
> +	.setxattr_fn = um_setxattr,
> +
> +	/* aio operations */
> +
> +	/* offline operations */
> +	.is_offline_fn = um_is_offline,
> +	.set_offline_fn = um_set_offline
> +};
> +
> +NTSTATUS vfs_unityed_media_init(void);
> +NTSTATUS vfs_unityed_media_init(void)
> +{
> +	NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
> +					"unityed_media", &vfs_um_fns);
> +	if (!NT_STATUS_IS_OK(ret)) {
> +		return ret;
> +	}
> +
> +	vfs_um_debug_level = debug_add_class("unityed_media");
> +
> +	if (vfs_um_debug_level == -1) {
> +		vfs_um_debug_level = DBGC_VFS;
> +		DEBUG(1, ("unityed_media_init: Couldn't register custom "
> +			  "debugging class.\n"));
> +	}
> +
> +	return ret;
> +}
> diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
> index de4947b..e2d4fde 100644
> --- a/source3/modules/wscript_build
> +++ b/source3/modules/wscript_build
> @@ -443,6 +443,15 @@ bld.SAMBA3_MODULE('vfs_media_harmony',
>                   internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_media_harmony'),
>                   enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_media_harmony'))
>  
> +bld.SAMBA3_MODULE('vfs_unityed_media',
> +                 subsystem='vfs',
> +                 source='vfs_unityed_media.c',
> +                 allow_warnings=True,
> +                 deps='samba-util',
> +                 init_function='',
> +                 internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_unityed_media'),
> +                 enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_unityed_media'))
> +
>  bld.SAMBA3_MODULE('vfs_dfs_samba4',
>                   subsystem='vfs',
>                   source='vfs_dfs_samba4.c',
> diff --git a/source3/wscript b/source3/wscript
> index bb57db5..84c33c4 100644
> --- a/source3/wscript
> +++ b/source3/wscript
> @@ -1572,7 +1572,7 @@ main() {
>                                        auth_script vfs_readahead vfs_xattr_tdb vfs_posix_eadb
>                                        vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb
>                                        vfs_smb_traffic_analyzer vfs_preopen vfs_catia vfs_scannedonly
> -				      vfs_media_harmony vfs_fruit
> +				      vfs_media_harmony vfs_unityed_media vfs_fruit
>  				      vfs_commit
>  				      vfs_worm
>                                        vfs_crossrename vfs_linux_xfs_sgid
> -- 
> 1.9.3
> 



More information about the samba-technical mailing list