| 1 | <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Chapter 10. VFS Modules</title><link rel="stylesheet" href="../samba.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><link rel="home" href="index.html" title="SAMBA Developers Guide"><link rel="up" href="pt03.html" title="Part III. Samba Subsystems"><link rel="prev" href="rpc-plugin.html" title="Chapter 9. RPC Pluggable Modules"><link rel="next" href="parsing.html" title="Chapter 11. The smb.conf file"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 10. VFS Modules</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="rpc-plugin.html">Prev</a> </td><th width="60%" align="center">Part III. Samba Subsystems</th><td width="20%" align="right"> <a accesskey="n" href="parsing.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 10. VFS Modules"><div class="titlepage"><div><div><h2 class="title"><a name="vfs"></a>Chapter 10. VFS Modules</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Alexander</span> <span class="surname">Bokovoy</span></h3><div class="affiliation"><div class="address"><p><code class="email"><<a class="email" href="mailto:ab@samba.org">ab@samba.org</a>></code></p></div></div></div></div><div><div class="author"><h3 class="author"><span class="firstname">Stefan</span> <span class="surname">Metzmacher</span></h3><div class="affiliation"><div class="address"><p><code class="email"><<a class="email" href="mailto:metze@samba.org">metze@samba.org</a>></code></p></div></div></div></div><div><p class="pubdate"> 27 May 2003 </p></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="vfs.html#id330849">The Samba (Posix) VFS layer</a></span></dt><dd><dl><dt><span class="sect2"><a href="vfs.html#id330877">The general interface</a></span></dt><dt><span class="sect2"><a href="vfs.html#id331145">Possible VFS operation layers</a></span></dt></dl></dd><dt><span class="sect1"><a href="vfs.html#id331195">The Interaction between the Samba VFS subsystem and the modules</a></span></dt><dd><dl><dt><span class="sect2"><a href="vfs.html#id331201">Initialization and registration</a></span></dt><dt><span class="sect2"><a href="vfs.html#id331328">How the Modules handle per connection data</a></span></dt></dl></dd><dt><span class="sect1"><a href="vfs.html#id331482">Upgrading to the New VFS Interface</a></span></dt><dd><dl><dt><span class="sect2"><a href="vfs.html#id331487">Upgrading from 2.2.* and 3.0alpha modules</a></span></dt></dl></dd><dt><span class="sect1"><a href="vfs.html#id331788">Some Notes</a></span></dt><dd><dl><dt><span class="sect2"><a href="vfs.html#id331793">Implement TRANSPARENT functions</a></span></dt><dt><span class="sect2"><a href="vfs.html#id331809">Implement OPAQUE functions</a></span></dt></dl></dd></dl></div><div class="sect1" title="The Samba (Posix) VFS layer"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id330849"></a>The Samba (Posix) VFS layer</h2></div></div></div><p>While most of Samba deployments are done using POSIX-compatible
|
|---|
| 2 | operating systems, there is clearly more to a file system than what is
|
|---|
| 3 | required by POSIX when it comes to adopting semantics of NT file
|
|---|
| 4 | system. Since Samba 2.2 all file-system related operations go through
|
|---|
| 5 | an abstraction layer for virtual file system (VFS) that is modelled
|
|---|
| 6 | after both POSIX and additional functions needed to transform NTFS
|
|---|
| 7 | semantics.
|
|---|
| 8 | </p><p>
|
|---|
| 9 | This abstraction layer now provides more features than a regular POSIX
|
|---|
| 10 | file system could fill in. It is not required that all of them should
|
|---|
| 11 | be implemented by your particular file system. However, when those
|
|---|
| 12 | features are available, Samba would advertize them to a CIFS client
|
|---|
| 13 | and they might be used by an application and in case of Windows client
|
|---|
| 14 | that might mean a client expects even more additional functionality
|
|---|
| 15 | when it encounters those features. There is a practical reason to
|
|---|
| 16 | allow handling of this snowfall without modifying the Samba core and
|
|---|
| 17 | it is fulfilled by providing an infrastructure to dynamically load VFS
|
|---|
| 18 | modules at run time.
|
|---|
| 19 | </p><p>Each VFS module could implement a number of VFS operations. The
|
|---|
| 20 | way it does it is irrelevant, only two things actually matter: whether
|
|---|
| 21 | specific implementation wants to cooperate with other modules'
|
|---|
| 22 | implementations or not, and whether module needs to store additional
|
|---|
| 23 | information that is specific to a context it is operating in. Multiple
|
|---|
| 24 | VFS modules could be loaded at the same time and it is even possible
|
|---|
| 25 | to load several instances of the same VFS module with different
|
|---|
| 26 | parameters.
|
|---|
| 27 | </p><div class="sect2" title="The general interface"><div class="titlepage"><div><div><h3 class="title"><a name="id330877"></a>The general interface</h3></div></div></div><p>A VFS module has three major components:
|
|---|
| 28 | </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><span class="emphasis"><em>An initialization function</em></span> that is
|
|---|
| 29 | called during the module load to register implemented
|
|---|
| 30 | operations.</p></li><li class="listitem"><p><span class="emphasis"><em>An operations table</em></span> representing a
|
|---|
| 31 | mapping between statically defined module functions and VFS layer
|
|---|
| 32 | operations.</p></li><li class="listitem"><p><span class="emphasis"><em>Module functions</em></span> that do actual
|
|---|
| 33 | work.</p></li></ul></div><p>
|
|---|
| 34 | </p><p>While this structure has been first applied to the VFS
|
|---|
| 35 | subsystem, it is now commonly used across all Samba 3 subsystems that
|
|---|
| 36 | support loadable modules. In fact, one module could provide a number
|
|---|
| 37 | of interfaces to different subsystems by exposing different
|
|---|
| 38 | <span class="emphasis"><em>operation tables</em></span> through separate
|
|---|
| 39 | <span class="emphasis"><em>initialization functions</em></span>.</p><p><span class="emphasis"><em>An initialization function</em></span> is used to
|
|---|
| 40 | register module with Samba run-time. As Samba internal structures and
|
|---|
| 41 | API are changed over lifetime, each released version has a VFS
|
|---|
| 42 | interface version that is increased as VFS development progresses or
|
|---|
| 43 | any of underlying Samba structures are changed in binary-incompatible
|
|---|
| 44 | way. When VFS module is compiled in, VFS interface version of that
|
|---|
| 45 | Samba environment is embedded into the module's binary object and is
|
|---|
| 46 | checked by the Samba core upon module load. If VFS interface number
|
|---|
| 47 | reported by the module isn't the same Samba core knows about, version
|
|---|
| 48 | conflict is detected and module dropped to avoid any potential memory
|
|---|
| 49 | corruption when accessing (changed) Samba structures.
|
|---|
| 50 | </p><p>Therefore, initialization function passes three parameters to the
|
|---|
| 51 | VFS registration function, <code class="literal">smb_register_vfs()</code>
|
|---|
| 52 | </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><span class="emphasis"><em>interface version number</em></span>, as constant
|
|---|
| 53 | <code class="literal">SMB_VFS_INTERFACE_VERSION</code>, </p></li><li class="listitem"><p><span class="emphasis"><em>module name</em></span>, under which Samba core
|
|---|
| 54 | will know it, and</p></li><li class="listitem"><p><span class="emphasis"><em>an operations' table</em></span>.</p></li></ul></div><p>
|
|---|
| 55 | </p><p>The <span class="emphasis"><em>operations' table</em></span> defines which
|
|---|
| 56 | functions in the module would correspond to specific VFS operations
|
|---|
| 57 | and how those functions would co-operate with the rest of VFS
|
|---|
| 58 | subsystem. Each operation could perform in a following ways:
|
|---|
| 59 | </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><span class="emphasis"><em>transparent</em></span>, meaning that while
|
|---|
| 60 | operation is overriden, the module will still call a previous
|
|---|
| 61 | implementation, before or after its own action. This mode is
|
|---|
| 62 | indicated by the constant
|
|---|
| 63 | <code class="literal">SMB_VFS_LAYER_TRANSPARENT</code>;</p></li><li class="listitem"><p><span class="emphasis"><em>opaque</em></span>, for the implementations that
|
|---|
| 64 | are terminating sequence of actions. For example, it is used to
|
|---|
| 65 | implement POSIX operation on top of non-POSIX file system or even
|
|---|
| 66 | not a file system at all, like a database for a personal audio
|
|---|
| 67 | collection. Use constant <code class="literal">SMB_VFS_LAYER_OPAQUE</code> for
|
|---|
| 68 | this mode;</p></li><li class="listitem"><p><span class="emphasis"><em>splitter</em></span>, a way when some file system
|
|---|
| 69 | activity is done in addition to the transparently calling previous
|
|---|
| 70 | implentation. This usually involves mangling the result of that call
|
|---|
| 71 | before returning it back to the caller. This mode is selected by
|
|---|
| 72 | <code class="literal">SMB_VFS_LAYER_SPLITTER</code> constant;</p></li><li class="listitem"><p><span class="emphasis"><em>logger</em></span> does not change anything or
|
|---|
| 73 | performs any additional VFS operations. When
|
|---|
| 74 | <span class="emphasis"><em>logger</em></span> module acts, information about
|
|---|
| 75 | operations is logged somewhere using an external facility (or
|
|---|
| 76 | Samba's own debugging tools) but not the VFS layer. In order to
|
|---|
| 77 | describe this type of activity use constant
|
|---|
| 78 | <code class="literal">SMB_VFS_LAYER_LOGGER</code>;
|
|---|
| 79 | </p></li><li class="listitem"><p>On contrary, <span class="emphasis"><em>scanner</em></span> module does call
|
|---|
| 80 | other VFS operations while processing the data that goes through the
|
|---|
| 81 | system. This type of operation is indicated by the
|
|---|
| 82 | <code class="literal">SMB_VFS_LAYER_SCANNER</code> constant.</p></li></ul></div><p>
|
|---|
| 83 | </p><p>Fundamentally, there are three types:
|
|---|
| 84 | <span class="emphasis"><em>transparent</em></span>, <span class="emphasis"><em>opaque</em></span>, and
|
|---|
| 85 | <span class="emphasis"><em>logger</em></span>. <span class="emphasis"><em>Splitter</em></span> and
|
|---|
| 86 | <span class="emphasis"><em>scanner</em></span> may confuse developers (and indeed they
|
|---|
| 87 | are confused as our experience has shown) but this separation is to
|
|---|
| 88 | better expose the nature of a module's actions. Most of modules
|
|---|
| 89 | developed so far are either one of those three fundamental types with
|
|---|
| 90 | transparent and opaque being prevalent.
|
|---|
| 91 | </p><p>
|
|---|
| 92 | Each VFS operation has a vfs_op_type, a function pointer and a handle
|
|---|
| 93 | pointer in the struct vfs_ops and tree macros to make it easier to
|
|---|
| 94 | call the operations. (Take a look at
|
|---|
| 95 | <code class="filename">include/vfs.h</code> and
|
|---|
| 96 | <code class="filename">include/vfs_macros.h</code>.)
|
|---|
| 97 | </p><pre class="programlisting">
|
|---|
| 98 | typedef enum _vfs_op_type {
|
|---|
| 99 | SMB_VFS_OP_NOOP = -1,
|
|---|
| 100 |
|
|---|
| 101 | ...
|
|---|
| 102 |
|
|---|
| 103 | /* File operations */
|
|---|
| 104 |
|
|---|
| 105 | SMB_VFS_OP_OPEN,
|
|---|
| 106 | SMB_VFS_OP_CLOSE,
|
|---|
| 107 | SMB_VFS_OP_READ,
|
|---|
| 108 | SMB_VFS_OP_WRITE,
|
|---|
| 109 | SMB_VFS_OP_LSEEK,
|
|---|
| 110 | SMB_VFS_OP_SENDFILE,
|
|---|
| 111 |
|
|---|
| 112 | ...
|
|---|
| 113 |
|
|---|
| 114 | SMB_VFS_OP_LAST
|
|---|
| 115 | } vfs_op_type;
|
|---|
| 116 | </pre><p>This struct contains the function and handle pointers for all operations.</p><pre class="programlisting">
|
|---|
| 117 | struct vfs_ops {
|
|---|
| 118 | struct vfs_fn_pointers {
|
|---|
| 119 | ...
|
|---|
| 120 |
|
|---|
| 121 | /* File operations */
|
|---|
| 122 |
|
|---|
| 123 | int (*open)(struct vfs_handle_struct *handle,
|
|---|
| 124 | struct connection_struct *conn,
|
|---|
| 125 | const char *fname, int flags, mode_t mode);
|
|---|
| 126 | int (*close)(struct vfs_handle_struct *handle,
|
|---|
| 127 | struct files_struct *fsp, int fd);
|
|---|
| 128 | ssize_t (*read)(struct vfs_handle_struct *handle,
|
|---|
| 129 | struct files_struct *fsp, int fd, void *data, size_t n);
|
|---|
| 130 | ssize_t (*write)(struct vfs_handle_struct *handle,
|
|---|
| 131 | struct files_struct *fsp, int fd,
|
|---|
| 132 | const void *data, size_t n);
|
|---|
| 133 | SMB_OFF_T (*lseek)(struct vfs_handle_struct *handle,
|
|---|
| 134 | struct files_struct *fsp, int fd,
|
|---|
| 135 | SMB_OFF_T offset, int whence);
|
|---|
| 136 | ssize_t (*sendfile)(struct vfs_handle_struct *handle,
|
|---|
| 137 | int tofd, files_struct *fsp, int fromfd,
|
|---|
| 138 | const DATA_BLOB *header, SMB_OFF_T offset, size_t count);
|
|---|
| 139 |
|
|---|
| 140 | ...
|
|---|
| 141 | } ops;
|
|---|
| 142 |
|
|---|
| 143 | struct vfs_handles_pointers {
|
|---|
| 144 | ...
|
|---|
| 145 |
|
|---|
| 146 | /* File operations */
|
|---|
| 147 |
|
|---|
| 148 | struct vfs_handle_struct *open;
|
|---|
| 149 | struct vfs_handle_struct *close;
|
|---|
| 150 | struct vfs_handle_struct *read;
|
|---|
| 151 | struct vfs_handle_struct *write;
|
|---|
| 152 | struct vfs_handle_struct *lseek;
|
|---|
| 153 | struct vfs_handle_struct *sendfile;
|
|---|
| 154 |
|
|---|
| 155 | ...
|
|---|
| 156 | } handles;
|
|---|
| 157 | };
|
|---|
| 158 | </pre><p>
|
|---|
| 159 | This macros SHOULD be used to call any vfs operation.
|
|---|
| 160 | DO NOT ACCESS conn->vfs.ops.* directly !!!
|
|---|
| 161 | </p><pre class="programlisting">
|
|---|
| 162 | ...
|
|---|
| 163 |
|
|---|
| 164 | /* File operations */
|
|---|
| 165 | #define SMB_VFS_OPEN(conn, fname, flags, mode) \
|
|---|
| 166 | ((conn)->vfs.ops.open((conn)->vfs.handles.open,\
|
|---|
| 167 | (conn), (fname), (flags), (mode)))
|
|---|
| 168 | #define SMB_VFS_CLOSE(fsp, fd) \
|
|---|
| 169 | ((fsp)->conn->vfs.ops.close(\
|
|---|
| 170 | (fsp)->conn->vfs.handles.close, (fsp), (fd)))
|
|---|
| 171 | #define SMB_VFS_READ(fsp, fd, data, n) \
|
|---|
| 172 | ((fsp)->conn->vfs.ops.read(\
|
|---|
| 173 | (fsp)->conn->vfs.handles.read,\
|
|---|
| 174 | (fsp), (fd), (data), (n)))
|
|---|
| 175 | #define SMB_VFS_WRITE(fsp, fd, data, n) \
|
|---|
| 176 | ((fsp)->conn->vfs.ops.write(\
|
|---|
| 177 | (fsp)->conn->vfs.handles.write,\
|
|---|
| 178 | (fsp), (fd), (data), (n)))
|
|---|
| 179 | #define SMB_VFS_LSEEK(fsp, fd, offset, whence) \
|
|---|
| 180 | ((fsp)->conn->vfs.ops.lseek(\
|
|---|
| 181 | (fsp)->conn->vfs.handles.lseek,\
|
|---|
| 182 | (fsp), (fd), (offset), (whence)))
|
|---|
| 183 | #define SMB_VFS_SENDFILE(tofd, fsp, fromfd, header, offset, count) \
|
|---|
| 184 | ((fsp)->conn->vfs.ops.sendfile(\
|
|---|
| 185 | (fsp)->conn->vfs.handles.sendfile,\
|
|---|
| 186 | (tofd), (fsp), (fromfd), (header), (offset), (count)))
|
|---|
| 187 |
|
|---|
| 188 | ...
|
|---|
| 189 | </pre></div><div class="sect2" title="Possible VFS operation layers"><div class="titlepage"><div><div><h3 class="title"><a name="id331145"></a>Possible VFS operation layers</h3></div></div></div><p>
|
|---|
| 190 | These values are used by the VFS subsystem when building the conn->vfs
|
|---|
| 191 | and conn->vfs_opaque structs for a connection with multiple VFS modules.
|
|---|
| 192 | Internally, Samba differentiates only opaque and transparent layers at this process.
|
|---|
| 193 | Other types are used for providing better diagnosing facilities.
|
|---|
| 194 | </p><p>
|
|---|
| 195 | Most modules will provide transparent layers. Opaque layer is for modules
|
|---|
| 196 | which implement actual file system calls (like DB-based VFS). For example,
|
|---|
| 197 | default POSIX VFS which is built in into Samba is an opaque VFS module.
|
|---|
| 198 | </p><p>
|
|---|
| 199 | Other layer types (logger, splitter, scanner) were designed to provide different
|
|---|
| 200 | degree of transparency and for diagnosing VFS module behaviour.
|
|---|
| 201 | </p><p>
|
|---|
| 202 | Each module can implement several layers at the same time provided that only
|
|---|
| 203 | one layer is used per each operation.
|
|---|
| 204 | </p><pre class="programlisting">
|
|---|
| 205 | typedef enum _vfs_op_layer {
|
|---|
| 206 | SMB_VFS_LAYER_NOOP = -1, /* - For using in VFS module to indicate end of array */
|
|---|
| 207 | /* of operations description */
|
|---|
| 208 | SMB_VFS_LAYER_OPAQUE = 0, /* - Final level, does not call anything beyond itself */
|
|---|
| 209 | SMB_VFS_LAYER_TRANSPARENT, /* - Normal operation, calls underlying layer after */
|
|---|
| 210 | /* possibly changing passed data */
|
|---|
| 211 | SMB_VFS_LAYER_LOGGER, /* - Logs data, calls underlying layer, logging may not */
|
|---|
| 212 | /* use Samba VFS */
|
|---|
| 213 | SMB_VFS_LAYER_SPLITTER, /* - Splits operation, calls underlying layer _and_ own facility, */
|
|---|
| 214 | /* then combines result */
|
|---|
| 215 | SMB_VFS_LAYER_SCANNER /* - Checks data and possibly initiates additional */
|
|---|
| 216 | /* file activity like logging to files _inside_ samba VFS */
|
|---|
| 217 | } vfs_op_layer;
|
|---|
| 218 | </pre></div></div><div class="sect1" title="The Interaction between the Samba VFS subsystem and the modules"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id331195"></a>The Interaction between the Samba VFS subsystem and the modules</h2></div></div></div><div class="sect2" title="Initialization and registration"><div class="titlepage"><div><div><h3 class="title"><a name="id331201"></a>Initialization and registration</h3></div></div></div><p>
|
|---|
| 219 | As each Samba module a VFS module should have a
|
|---|
| 220 | </p><pre class="programlisting">NTSTATUS vfs_example_init(void);</pre><p> function if it's staticly linked to samba or
|
|---|
| 221 | </p><pre class="programlisting">NTSTATUS init_module(void);</pre><p> function if it's a shared module.
|
|---|
| 222 | </p><p>
|
|---|
| 223 | This should be the only non static function inside the module.
|
|---|
| 224 | Global variables should also be static!
|
|---|
| 225 | </p><p>
|
|---|
| 226 | The module should register its functions via the
|
|---|
| 227 | </p><pre class="programlisting">
|
|---|
| 228 | NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples);
|
|---|
| 229 | </pre><p> function.
|
|---|
| 230 | </p><div class="variablelist"><dl><dt><span class="term">version</span></dt><dd><p>should be filled with SMB_VFS_INTERFACE_VERSION</p></dd><dt><span class="term">name</span></dt><dd><p>this is the name witch can be listed in the
|
|---|
| 231 | <code class="literal">vfs objects</code> parameter to use this module.</p></dd><dt><span class="term">vfs_op_tuples</span></dt><dd><p>
|
|---|
| 232 | this is an array of vfs_op_tuple's.
|
|---|
| 233 | (vfs_op_tuples is descripted in details below.)
|
|---|
| 234 | </p></dd></dl></div><p>
|
|---|
| 235 | For each operation the module wants to provide it has a entry in the
|
|---|
| 236 | vfs_op_tuple array.
|
|---|
| 237 | </p><pre class="programlisting">
|
|---|
| 238 | typedef struct _vfs_op_tuple {
|
|---|
| 239 | void* op;
|
|---|
| 240 | vfs_op_type type;
|
|---|
| 241 | vfs_op_layer layer;
|
|---|
| 242 | } vfs_op_tuple;
|
|---|
| 243 | </pre><div class="variablelist"><dl><dt><span class="term">op</span></dt><dd><p>the function pointer to the specified function.</p></dd><dt><span class="term">type</span></dt><dd><p>the vfs_op_type of the function to specified witch operation the function provides.</p></dd><dt><span class="term">layer</span></dt><dd><p>the vfs_op_layer in whitch the function operates.</p></dd></dl></div><p>A simple example:</p><pre class="programlisting">
|
|---|
| 244 | static vfs_op_tuple example_op_tuples[] = {
|
|---|
| 245 | {SMB_VFS_OP(example_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
|
|---|
| 246 | {SMB_VFS_OP(example_disconnect), SMB_VFS_OP_DISCONNECT, SMB_VFS_LAYER_TRANSPARENT},
|
|---|
| 247 |
|
|---|
| 248 | {SMB_VFS_OP(example_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_OPAQUE},
|
|---|
| 249 |
|
|---|
| 250 | /* This indicates the end of the array */
|
|---|
| 251 | {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
|
|---|
| 252 | };
|
|---|
| 253 |
|
|---|
| 254 | NTSTATUS init_module(void)
|
|---|
| 255 | {
|
|---|
| 256 | return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "example", example_op_tuples);
|
|---|
| 257 | }
|
|---|
| 258 | </pre></div><div class="sect2" title="How the Modules handle per connection data"><div class="titlepage"><div><div><h3 class="title"><a name="id331328"></a>How the Modules handle per connection data</h3></div></div></div><p>Each VFS function has as first parameter a pointer to the modules vfs_handle_struct.
|
|---|
| 259 | </p><pre class="programlisting">
|
|---|
| 260 | typedef struct vfs_handle_struct {
|
|---|
| 261 | struct vfs_handle_struct *next, *prev;
|
|---|
| 262 | const char *param;
|
|---|
| 263 | struct vfs_ops vfs_next;
|
|---|
| 264 | struct connection_struct *conn;
|
|---|
| 265 | void *data;
|
|---|
| 266 | void (*free_data)(void **data);
|
|---|
| 267 | } vfs_handle_struct;
|
|---|
| 268 | </pre><div class="variablelist"><dl><dt><span class="term">param</span></dt><dd><p>this is the module parameter specified in the <code class="literal">vfs objects</code> parameter.</p><p>e.g. for 'vfs objects = example:test' param would be "test".</p></dd><dt><span class="term">vfs_next</span></dt><dd><p>This vfs_ops struct contains the information for calling the next module operations.
|
|---|
| 269 | Use the SMB_VFS_NEXT_* macros to call a next module operations and
|
|---|
| 270 | don't access handle->vfs_next.ops.* directly!</p></dd><dt><span class="term">conn</span></dt><dd><p>This is a pointer back to the connection_struct to witch the handle belongs.</p></dd><dt><span class="term">data</span></dt><dd><p>This is a pointer for holding module private data.
|
|---|
| 271 | You can alloc data with connection life time on the handle->conn->mem_ctx TALLOC_CTX.
|
|---|
| 272 | But you can also manage the memory allocation yourself.</p></dd><dt><span class="term">free_data</span></dt><dd><p>This is a function pointer to a function that free's the module private data.
|
|---|
| 273 | If you talloc your private data on the TALLOC_CTX handle->conn->mem_ctx,
|
|---|
| 274 | you can set this function pointer to NULL.</p></dd></dl></div><p>Some useful MACROS for handle private data.
|
|---|
| 275 | </p><pre class="programlisting">
|
|---|
| 276 | #define SMB_VFS_HANDLE_GET_DATA(handle, datap, type, ret) { \
|
|---|
| 277 | if (!(handle)||((datap=(type *)(handle)->data)==NULL)) { \
|
|---|
| 278 | DEBUG(0,("%s() failed to get vfs_handle->data!\n",FUNCTION_MACRO)); \
|
|---|
| 279 | ret; \
|
|---|
| 280 | } \
|
|---|
| 281 | }
|
|---|
| 282 |
|
|---|
| 283 | #define SMB_VFS_HANDLE_SET_DATA(handle, datap, free_fn, type, ret) { \
|
|---|
| 284 | if (!(handle)) { \
|
|---|
| 285 | DEBUG(0,("%s() failed to set handle->data!\n",FUNCTION_MACRO)); \
|
|---|
| 286 | ret; \
|
|---|
| 287 | } else { \
|
|---|
| 288 | if ((handle)->free_data) { \
|
|---|
| 289 | (handle)->free_data(&(handle)->data); \
|
|---|
| 290 | } \
|
|---|
| 291 | (handle)->data = (void *)datap; \
|
|---|
| 292 | (handle)->free_data = free_fn; \
|
|---|
| 293 | } \
|
|---|
| 294 | }
|
|---|
| 295 |
|
|---|
| 296 | #define SMB_VFS_HANDLE_FREE_DATA(handle) { \
|
|---|
| 297 | if ((handle) && (handle)->free_data) { \
|
|---|
| 298 | (handle)->free_data(&(handle)->data); \
|
|---|
| 299 | } \
|
|---|
| 300 | }
|
|---|
| 301 | </pre><p>How SMB_VFS_LAYER_TRANSPARENT functions can call the SMB_VFS_LAYER_OPAQUE functions.</p><p>The easiest way to do this is to use the SMB_VFS_OPAQUE_* macros.
|
|---|
| 302 | </p><pre class="programlisting">
|
|---|
| 303 | ...
|
|---|
| 304 | /* File operations */
|
|---|
| 305 | #define SMB_VFS_OPAQUE_OPEN(conn, fname, flags, mode) \
|
|---|
| 306 | ((conn)->vfs_opaque.ops.open(\
|
|---|
| 307 | (conn)->vfs_opaque.handles.open,\
|
|---|
| 308 | (conn), (fname), (flags), (mode)))
|
|---|
| 309 | #define SMB_VFS_OPAQUE_CLOSE(fsp, fd) \
|
|---|
| 310 | ((fsp)->conn->vfs_opaque.ops.close(\
|
|---|
| 311 | (fsp)->conn->vfs_opaque.handles.close,\
|
|---|
| 312 | (fsp), (fd)))
|
|---|
| 313 | #define SMB_VFS_OPAQUE_READ(fsp, fd, data, n) \
|
|---|
| 314 | ((fsp)->conn->vfs_opaque.ops.read(\
|
|---|
| 315 | (fsp)->conn->vfs_opaque.handles.read,\
|
|---|
| 316 | (fsp), (fd), (data), (n)))
|
|---|
| 317 | #define SMB_VFS_OPAQUE_WRITE(fsp, fd, data, n) \
|
|---|
| 318 | ((fsp)->conn->vfs_opaque.ops.write(\
|
|---|
| 319 | (fsp)->conn->vfs_opaque.handles.write,\
|
|---|
| 320 | (fsp), (fd), (data), (n)))
|
|---|
| 321 | #define SMB_VFS_OPAQUE_LSEEK(fsp, fd, offset, whence) \
|
|---|
| 322 | ((fsp)->conn->vfs_opaque.ops.lseek(\
|
|---|
| 323 | (fsp)->conn->vfs_opaque.handles.lseek,\
|
|---|
| 324 | (fsp), (fd), (offset), (whence)))
|
|---|
| 325 | #define SMB_VFS_OPAQUE_SENDFILE(tofd, fsp, fromfd, header, offset, count) \
|
|---|
| 326 | ((fsp)->conn->vfs_opaque.ops.sendfile(\
|
|---|
| 327 | (fsp)->conn->vfs_opaque.handles.sendfile,\
|
|---|
| 328 | (tofd), (fsp), (fromfd), (header), (offset), (count)))
|
|---|
| 329 | ...
|
|---|
| 330 | </pre><p>How SMB_VFS_LAYER_TRANSPARENT functions can call the next modules functions.</p><p>The easiest way to do this is to use the SMB_VFS_NEXT_* macros.
|
|---|
| 331 | </p><pre class="programlisting">
|
|---|
| 332 | ...
|
|---|
| 333 | /* File operations */
|
|---|
| 334 | #define SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode) \
|
|---|
| 335 | ((handle)->vfs_next.ops.open(\
|
|---|
| 336 | (handle)->vfs_next.handles.open,\
|
|---|
| 337 | (conn), (fname), (flags), (mode)))
|
|---|
| 338 | #define SMB_VFS_NEXT_CLOSE(handle, fsp, fd) \
|
|---|
| 339 | ((handle)->vfs_next.ops.close(\
|
|---|
| 340 | (handle)->vfs_next.handles.close,\
|
|---|
| 341 | (fsp), (fd)))
|
|---|
| 342 | #define SMB_VFS_NEXT_READ(handle, fsp, fd, data, n) \
|
|---|
| 343 | ((handle)->vfs_next.ops.read(\
|
|---|
| 344 | (handle)->vfs_next.handles.read,\
|
|---|
| 345 | (fsp), (fd), (data), (n)))
|
|---|
| 346 | #define SMB_VFS_NEXT_WRITE(handle, fsp, fd, data, n) \
|
|---|
| 347 | ((handle)->vfs_next.ops.write(\
|
|---|
| 348 | (handle)->vfs_next.handles.write,\
|
|---|
| 349 | (fsp), (fd), (data), (n)))
|
|---|
| 350 | #define SMB_VFS_NEXT_LSEEK(handle, fsp, fd, offset, whence) \
|
|---|
| 351 | ((handle)->vfs_next.ops.lseek(\
|
|---|
| 352 | (handle)->vfs_next.handles.lseek,\
|
|---|
| 353 | (fsp), (fd), (offset), (whence)))
|
|---|
| 354 | #define SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, fromfd, header, offset, count) \
|
|---|
| 355 | ((handle)->vfs_next.ops.sendfile(\
|
|---|
| 356 | (handle)->vfs_next.handles.sendfile,\
|
|---|
| 357 | (tofd), (fsp), (fromfd), (header), (offset), (count)))
|
|---|
| 358 | ...
|
|---|
| 359 | </pre></div></div><div class="sect1" title="Upgrading to the New VFS Interface"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id331482"></a>Upgrading to the New VFS Interface</h2></div></div></div><div class="sect2" title="Upgrading from 2.2.* and 3.0alpha modules"><div class="titlepage"><div><div><h3 class="title"><a name="id331487"></a>Upgrading from 2.2.* and 3.0alpha modules</h3></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
|
|---|
| 360 | Add "vfs_handle_struct *handle, " as first parameter to all vfs operation functions.
|
|---|
| 361 | e.g. example_connect(connection_struct *conn, const char *service, const char *user);
|
|---|
| 362 | -> example_connect(vfs_handle_struct *handle, connection_struct *conn, const char *service, const char *user);
|
|---|
| 363 | </p></li><li class="listitem"><p>
|
|---|
| 364 | Replace "default_vfs_ops." with "smb_vfs_next_".
|
|---|
| 365 | e.g. default_vfs_ops.connect(conn, service, user);
|
|---|
| 366 | -> smb_vfs_next_connect(conn, service, user);
|
|---|
| 367 | </p></li><li class="listitem"><p>
|
|---|
| 368 | Uppercase all "smb_vfs_next_*" functions.
|
|---|
| 369 | e.g. smb_vfs_next_connect(conn, service, user);
|
|---|
| 370 | -> SMB_VFS_NEXT_CONNECT(conn, service, user);
|
|---|
| 371 | </p></li><li class="listitem"><p>
|
|---|
| 372 | Add "handle, " as first parameter to all SMB_VFS_NEXT_*() calls.
|
|---|
| 373 | e.g. SMB_VFS_NEXT_CONNECT(conn, service, user);
|
|---|
| 374 | -> SMB_VFS_NEXT_CONNECT(handle, conn, service, user);
|
|---|
| 375 | </p></li><li class="listitem"><p>
|
|---|
| 376 | (Only for 2.2.* modules)
|
|---|
| 377 | Convert the old struct vfs_ops example_ops to
|
|---|
| 378 | a vfs_op_tuple example_op_tuples[] array.
|
|---|
| 379 | e.g.
|
|---|
| 380 | </p><pre class="programlisting">
|
|---|
| 381 | struct vfs_ops example_ops = {
|
|---|
| 382 | /* Disk operations */
|
|---|
| 383 | example_connect, /* connect */
|
|---|
| 384 | example_disconnect, /* disconnect */
|
|---|
| 385 | NULL, /* disk free *
|
|---|
| 386 | /* Directory operations */
|
|---|
| 387 | NULL, /* opendir */
|
|---|
| 388 | NULL, /* readdir */
|
|---|
| 389 | NULL, /* mkdir */
|
|---|
| 390 | NULL, /* rmdir */
|
|---|
| 391 | NULL, /* closedir */
|
|---|
| 392 | /* File operations */
|
|---|
| 393 | NULL, /* open */
|
|---|
| 394 | NULL, /* close */
|
|---|
| 395 | NULL, /* read */
|
|---|
| 396 | NULL, /* write */
|
|---|
| 397 | NULL, /* lseek */
|
|---|
| 398 | NULL, /* sendfile */
|
|---|
| 399 | NULL, /* rename */
|
|---|
| 400 | NULL, /* fsync */
|
|---|
| 401 | example_stat, /* stat */
|
|---|
| 402 | example_fstat, /* fstat */
|
|---|
| 403 | example_lstat, /* lstat */
|
|---|
| 404 | NULL, /* unlink */
|
|---|
| 405 | NULL, /* chmod */
|
|---|
| 406 | NULL, /* fchmod */
|
|---|
| 407 | NULL, /* chown */
|
|---|
| 408 | NULL, /* fchown */
|
|---|
| 409 | NULL, /* chdir */
|
|---|
| 410 | NULL, /* getwd */
|
|---|
| 411 | NULL, /* utime */
|
|---|
| 412 | NULL, /* ftruncate */
|
|---|
| 413 | NULL, /* lock */
|
|---|
| 414 | NULL, /* symlink */
|
|---|
| 415 | NULL, /* readlink */
|
|---|
| 416 | NULL, /* link */
|
|---|
| 417 | NULL, /* mknod */
|
|---|
| 418 | NULL, /* realpath */
|
|---|
| 419 | NULL, /* fget_nt_acl */
|
|---|
| 420 | NULL, /* get_nt_acl */
|
|---|
| 421 | NULL, /* fset_nt_acl */
|
|---|
| 422 | NULL, /* set_nt_acl */
|
|---|
| 423 |
|
|---|
| 424 | NULL, /* chmod_acl */
|
|---|
| 425 | NULL, /* fchmod_acl */
|
|---|
| 426 |
|
|---|
| 427 | NULL, /* sys_acl_get_entry */
|
|---|
| 428 | NULL, /* sys_acl_get_tag_type */
|
|---|
| 429 | NULL, /* sys_acl_get_permset */
|
|---|
| 430 | NULL, /* sys_acl_get_qualifier */
|
|---|
| 431 | NULL, /* sys_acl_get_file */
|
|---|
| 432 | NULL, /* sys_acl_get_fd */
|
|---|
| 433 | NULL, /* sys_acl_clear_perms */
|
|---|
| 434 | NULL, /* sys_acl_add_perm */
|
|---|
| 435 | NULL, /* sys_acl_to_text */
|
|---|
| 436 | NULL, /* sys_acl_init */
|
|---|
| 437 | NULL, /* sys_acl_create_entry */
|
|---|
| 438 | NULL, /* sys_acl_set_tag_type */
|
|---|
| 439 | NULL, /* sys_acl_set_qualifier */
|
|---|
| 440 | NULL, /* sys_acl_set_permset */
|
|---|
| 441 | NULL, /* sys_acl_valid */
|
|---|
| 442 | NULL, /* sys_acl_set_file */
|
|---|
| 443 | NULL, /* sys_acl_set_fd */
|
|---|
| 444 | NULL, /* sys_acl_delete_def_file */
|
|---|
| 445 | NULL, /* sys_acl_get_perm */
|
|---|
| 446 | NULL, /* sys_acl_free_text */
|
|---|
| 447 | NULL, /* sys_acl_free_acl */
|
|---|
| 448 | NULL /* sys_acl_free_qualifier */
|
|---|
| 449 | };
|
|---|
| 450 | </pre><p>
|
|---|
| 451 | ->
|
|---|
| 452 | </p><pre class="programlisting">
|
|---|
| 453 | static vfs_op_tuple example_op_tuples[] = {
|
|---|
| 454 | {SMB_VFS_OP(example_connect), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
|
|---|
| 455 | {SMB_VFS_OP(example_disconnect), SMB_VFS_OP_DISCONNECT, SMB_VFS_LAYER_TRANSPARENT},
|
|---|
| 456 |
|
|---|
| 457 | {SMB_VFS_OP(example_fstat), SMB_VFS_OP_FSTAT, SMB_VFS_LAYER_TRANSPARENT},
|
|---|
| 458 | {SMB_VFS_OP(example_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT},
|
|---|
| 459 | {SMB_VFS_OP(example_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT},
|
|---|
| 460 |
|
|---|
| 461 | {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
|
|---|
| 462 | };
|
|---|
| 463 | </pre><p>
|
|---|
| 464 | </p></li><li class="listitem"><p>
|
|---|
| 465 | Move the example_op_tuples[] array to the end of the file.
|
|---|
| 466 | </p></li><li class="listitem"><p>
|
|---|
| 467 | Add the init_module() function at the end of the file.
|
|---|
| 468 | e.g.
|
|---|
| 469 | </p><pre class="programlisting">
|
|---|
| 470 | NTSTATUS init_module(void)
|
|---|
| 471 | {
|
|---|
| 472 | return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,"example",example_op_tuples);
|
|---|
| 473 | }
|
|---|
| 474 | </pre><p>
|
|---|
| 475 | </p></li><li class="listitem"><p>
|
|---|
| 476 | Check if your vfs_init() function does more then just prepare the vfs_ops structs or
|
|---|
| 477 | remember the struct smb_vfs_handle_struct.
|
|---|
| 478 | </p><table border="0" summary="Simple list" class="simplelist"><tr><td>If NOT you can remove the vfs_init() function.</td></tr><tr><td>If YES decide if you want to move the code to the example_connect() operation or to the init_module(). And then remove vfs_init().
|
|---|
| 479 | e.g. a debug class registration should go into init_module() and the allocation of private data should go to example_connect().</td></tr></table><p>
|
|---|
| 480 | </p></li><li class="listitem"><p>
|
|---|
| 481 | (Only for 3.0alpha* modules)
|
|---|
| 482 | Check if your vfs_done() function contains needed code.
|
|---|
| 483 | </p><table border="0" summary="Simple list" class="simplelist"><tr><td>If NOT you can remove the vfs_done() function.</td></tr><tr><td>If YES decide if you can move the code to the example_disconnect() operation. Otherwise register a SMB_EXIT_EVENT with smb_register_exit_event(); (Described in the <a class="link" href="modules.html" title="Chapter 8. Modules">modules section</a>) And then remove vfs_done(). e.g. the freeing of private data should go to example_disconnect().
|
|---|
| 484 | </td></tr></table><p>
|
|---|
| 485 | </p></li><li class="listitem"><p>
|
|---|
| 486 | Check if you have any global variables left.
|
|---|
| 487 | Decide if it wouldn't be better to have this data on a connection basis.
|
|---|
| 488 | </p><table border="0" summary="Simple list" class="simplelist"><tr><td>If NOT leave them as they are. (e.g. this could be the variable for the private debug class.)</td></tr><tr><td>If YES pack all this data into a struct. You can use handle->data to point to such a struct on a per connection basis.</td></tr></table><p>
|
|---|
| 489 |
|
|---|
| 490 | e.g. if you have such a struct:
|
|---|
| 491 | </p><pre class="programlisting">
|
|---|
| 492 | struct example_privates {
|
|---|
| 493 | char *some_string;
|
|---|
| 494 | int db_connection;
|
|---|
| 495 | };
|
|---|
| 496 | </pre><p>
|
|---|
| 497 | first way of doing it:
|
|---|
| 498 | </p><pre class="programlisting">
|
|---|
| 499 | static int example_connect(vfs_handle_struct *handle,
|
|---|
| 500 | connection_struct *conn, const char *service,
|
|---|
| 501 | const char* user)
|
|---|
| 502 | {
|
|---|
| 503 | struct example_privates *data = NULL;
|
|---|
| 504 |
|
|---|
| 505 | /* alloc our private data */
|
|---|
| 506 | data = (struct example_privates *)talloc_zero(conn->mem_ctx, sizeof(struct example_privates));
|
|---|
| 507 | if (!data) {
|
|---|
| 508 | DEBUG(0,("talloc_zero() failed\n"));
|
|---|
| 509 | return -1;
|
|---|
| 510 | }
|
|---|
| 511 |
|
|---|
| 512 | /* init out private data */
|
|---|
| 513 | data->some_string = talloc_strdup(conn->mem_ctx,"test");
|
|---|
| 514 | if (!data->some_string) {
|
|---|
| 515 | DEBUG(0,("talloc_strdup() failed\n"));
|
|---|
| 516 | return -1;
|
|---|
| 517 | }
|
|---|
| 518 |
|
|---|
| 519 | data->db_connection = open_db_conn();
|
|---|
| 520 |
|
|---|
| 521 | /* and now store the private data pointer in handle->data
|
|---|
| 522 | * we don't need to specify a free_function here because
|
|---|
| 523 | * we use the connection TALLOC context.
|
|---|
| 524 | * (return -1 if something failed.)
|
|---|
| 525 | */
|
|---|
| 526 | VFS_HANDLE_SET_DATA(handle, data, NULL, struct example_privates, return -1);
|
|---|
| 527 |
|
|---|
| 528 | return SMB_VFS_NEXT_CONNECT(handle,conn,service,user);
|
|---|
| 529 | }
|
|---|
| 530 |
|
|---|
| 531 | static int example_close(vfs_handle_struct *handle, files_struct *fsp, int fd)
|
|---|
| 532 | {
|
|---|
| 533 | struct example_privates *data = NULL;
|
|---|
| 534 |
|
|---|
| 535 | /* get the pointer to our private data
|
|---|
| 536 | * return -1 if something failed
|
|---|
| 537 | */
|
|---|
| 538 | SMB_VFS_HANDLE_GET_DATA(handle, data, struct example_privates, return -1);
|
|---|
| 539 |
|
|---|
| 540 | /* do something here...*/
|
|---|
| 541 | DEBUG(0,("some_string: %s\n",data->some_string));
|
|---|
| 542 |
|
|---|
| 543 | return SMB_VFS_NEXT_CLOSE(handle, fsp, fd);
|
|---|
| 544 | }
|
|---|
| 545 | </pre><p>
|
|---|
| 546 | second way of doing it:
|
|---|
| 547 | </p><pre class="programlisting">
|
|---|
| 548 | static void free_example_privates(void **datap)
|
|---|
| 549 | {
|
|---|
| 550 | struct example_privates *data = (struct example_privates *)*datap;
|
|---|
| 551 |
|
|---|
| 552 | SAFE_FREE(data->some_string);
|
|---|
| 553 | SAFE_FREE(data);
|
|---|
| 554 |
|
|---|
| 555 | *datap = NULL;
|
|---|
| 556 |
|
|---|
| 557 | return;
|
|---|
| 558 | }
|
|---|
| 559 |
|
|---|
| 560 | static int example_connect(vfs_handle_struct *handle,
|
|---|
| 561 | connection_struct *conn, const char *service,
|
|---|
| 562 | const char* user)
|
|---|
| 563 | {
|
|---|
| 564 | struct example_privates *data = NULL;
|
|---|
| 565 |
|
|---|
| 566 | /* alloc our private data */
|
|---|
| 567 | data = (struct example_privates *)malloc(sizeof(struct example_privates));
|
|---|
| 568 | if (!data) {
|
|---|
| 569 | DEBUG(0,("malloc() failed\n"));
|
|---|
| 570 | return -1;
|
|---|
| 571 | }
|
|---|
| 572 |
|
|---|
| 573 | /* init out private data */
|
|---|
| 574 | data->some_string = strdup("test");
|
|---|
| 575 | if (!data->some_string) {
|
|---|
| 576 | DEBUG(0,("strdup() failed\n"));
|
|---|
| 577 | return -1;
|
|---|
| 578 | }
|
|---|
| 579 |
|
|---|
| 580 | data->db_connection = open_db_conn();
|
|---|
| 581 |
|
|---|
| 582 | /* and now store the private data pointer in handle->data
|
|---|
| 583 | * we need to specify a free_function because we used malloc() and strdup().
|
|---|
| 584 | * (return -1 if something failed.)
|
|---|
| 585 | */
|
|---|
| 586 | SMB_VFS_HANDLE_SET_DATA(handle, data, free_example_privates, struct example_privates, return -1);
|
|---|
| 587 |
|
|---|
| 588 | return SMB_VFS_NEXT_CONNECT(handle,conn,service,user);
|
|---|
| 589 | }
|
|---|
| 590 |
|
|---|
| 591 | static int example_close(vfs_handle_struct *handle, files_struct *fsp, int fd)
|
|---|
| 592 | {
|
|---|
| 593 | struct example_privates *data = NULL;
|
|---|
| 594 |
|
|---|
| 595 | /* get the pointer to our private data
|
|---|
| 596 | * return -1 if something failed
|
|---|
| 597 | */
|
|---|
| 598 | SMB_VFS_HANDLE_GET_DATA(handle, data, struct example_privates, return -1);
|
|---|
| 599 |
|
|---|
| 600 | /* do something here...*/
|
|---|
| 601 | DEBUG(0,("some_string: %s\n",data->some_string));
|
|---|
| 602 |
|
|---|
| 603 | return SMB_VFS_NEXT_CLOSE(handle, fsp, fd);
|
|---|
| 604 | }
|
|---|
| 605 | </pre><p>
|
|---|
| 606 | </p></li><li class="listitem"><p>
|
|---|
| 607 | To make it easy to build 3rd party modules it would be useful to provide
|
|---|
| 608 | configure.in, (configure), install.sh and Makefile.in with the module.
|
|---|
| 609 | (Take a look at the example in <code class="filename">examples/VFS</code>.)
|
|---|
| 610 | </p><p>
|
|---|
| 611 | The configure script accepts <code class="option">--with-samba-source</code> to specify
|
|---|
| 612 | the path to the samba source tree.
|
|---|
| 613 | It also accept <code class="option">--enable-developer</code> which lets the compiler
|
|---|
| 614 | give you more warnings.
|
|---|
| 615 | </p><p>
|
|---|
| 616 | The idea is that you can extend this
|
|---|
| 617 | <code class="filename">configure.in</code> and <code class="filename">Makefile.in</code> scripts
|
|---|
| 618 | for your module.
|
|---|
| 619 | </p></li><li class="listitem"><p>
|
|---|
| 620 | Compiling & Testing...
|
|---|
| 621 | </p><table border="0" summary="Simple list" class="simplelist"><tr><td><strong class="userinput"><code>./configure <code class="option">--enable-developer</code></code></strong> ...</td></tr><tr><td><strong class="userinput"><code>make</code></strong></td></tr><tr><td>Try to fix all compiler warnings</td></tr><tr><td><strong class="userinput"><code>make</code></strong></td></tr><tr><td>Testing, Testing, Testing ...</td></tr></table><p>
|
|---|
| 622 | </p></li></ol></div></div></div><div class="sect1" title="Some Notes"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id331788"></a>Some Notes</h2></div></div></div><div class="sect2" title="Implement TRANSPARENT functions"><div class="titlepage"><div><div><h3 class="title"><a name="id331793"></a>Implement TRANSPARENT functions</h3></div></div></div><p>
|
|---|
| 623 | Avoid writing functions like this:
|
|---|
| 624 |
|
|---|
| 625 | </p><pre class="programlisting">
|
|---|
| 626 | static int example_close(vfs_handle_struct *handle, files_struct *fsp, int fd)
|
|---|
| 627 | {
|
|---|
| 628 | return SMB_VFS_NEXT_CLOSE(handle, fsp, fd);
|
|---|
| 629 | }
|
|---|
| 630 | </pre><p>
|
|---|
| 631 |
|
|---|
| 632 | Overload only the functions you really need to!
|
|---|
| 633 | </p></div><div class="sect2" title="Implement OPAQUE functions"><div class="titlepage"><div><div><h3 class="title"><a name="id331809"></a>Implement OPAQUE functions</h3></div></div></div><p>
|
|---|
| 634 | If you want to just implement a better version of a
|
|---|
| 635 | default samba opaque function
|
|---|
| 636 | (e.g. like a disk_free() function for a special filesystem)
|
|---|
| 637 | it's ok to just overload that specific function.
|
|---|
| 638 | </p><p>
|
|---|
| 639 | If you want to implement a database filesystem or
|
|---|
| 640 | something different from a posix filesystem.
|
|---|
| 641 | Make sure that you overload every vfs operation!!!
|
|---|
| 642 | </p><p>
|
|---|
| 643 | Functions your FS does not support should be overloaded by something like this:
|
|---|
| 644 | e.g. for a readonly filesystem.
|
|---|
| 645 | </p><pre class="programlisting">
|
|---|
| 646 | static int example_rename(vfs_handle_struct *handle, connection_struct *conn,
|
|---|
| 647 | char *oldname, char *newname)
|
|---|
| 648 | {
|
|---|
| 649 | DEBUG(10,("function rename() not allowed on vfs 'example'\n"));
|
|---|
| 650 | errno = ENOSYS;
|
|---|
| 651 | return -1;
|
|---|
| 652 | }
|
|---|
| 653 | </pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="rpc-plugin.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="parsing.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 9. RPC Pluggable Modules </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 11. The smb.conf file</td></tr></table></div></body></html>
|
|---|