2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 this implements most of the POSIX NTVFS backend
24 This is the default backend
28 #include "vfs_posix.h"
29 #include "librpc/gen_ndr/security.h"
30 #include "lib/tdb/include/tdb.h"
32 #include "libcli/security/security.h"
33 #include "lib/events/events.h"
37 setup config options for a posix share
39 static void pvfs_setup_options(struct pvfs_state *pvfs)
41 struct share_config *scfg = pvfs->ntvfs->ctx->config;
44 if (share_bool_option(scfg, SHARE_MAP_HIDDEN, SHARE_MAP_HIDDEN_DEFAULT))
45 pvfs->flags |= PVFS_FLAG_MAP_HIDDEN;
46 if (share_bool_option(scfg, SHARE_MAP_ARCHIVE, SHARE_MAP_ARCHIVE_DEFAULT))
47 pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE;
48 if (share_bool_option(scfg, SHARE_MAP_SYSTEM, SHARE_MAP_SYSTEM_DEFAULT))
49 pvfs->flags |= PVFS_FLAG_MAP_SYSTEM;
50 if (share_bool_option(scfg, SHARE_READONLY, SHARE_READONLY_DEFAULT))
51 pvfs->flags |= PVFS_FLAG_READONLY;
52 if (share_bool_option(scfg, SHARE_STRICT_SYNC, SHARE_STRICT_SYNC_DEFAULT))
53 pvfs->flags |= PVFS_FLAG_STRICT_SYNC;
54 if (share_bool_option(scfg, SHARE_STRICT_LOCKING, SHARE_STRICT_LOCKING_DEFAULT))
55 pvfs->flags |= PVFS_FLAG_STRICT_LOCKING;
56 if (share_bool_option(scfg, SHARE_CI_FILESYSTEM, SHARE_CI_FILESYSTEM_DEFAULT))
57 pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM;
58 if (share_bool_option(scfg, PVFS_FAKE_OPLOCKS, PVFS_FAKE_OPLOCKS_DEFAULT))
59 pvfs->flags |= PVFS_FLAG_FAKE_OPLOCKS;
60 if (share_bool_option(scfg, PVFS_AIO, False))
61 pvfs->flags |= PVFS_FLAG_LINUX_AIO;
63 /* file perm options */
64 pvfs->options.create_mask = share_int_option(scfg,
66 SHARE_CREATE_MASK_DEFAULT);
67 pvfs->options.dir_mask = share_int_option(scfg,
69 SHARE_DIR_MASK_DEFAULT);
70 pvfs->options.force_dir_mode = share_int_option(scfg,
72 SHARE_FORCE_DIR_MODE_DEFAULT);
73 pvfs->options.force_create_mode = share_int_option(scfg,
74 SHARE_FORCE_CREATE_MODE,
75 SHARE_FORCE_CREATE_MODE_DEFAULT);
76 /* this must be a power of 2 */
77 pvfs->alloc_size_rounding = share_int_option(scfg,
78 PVFS_ALLOCATION_ROUNDING,
79 PVFS_ALLOCATION_ROUNDING_DEFAULT);
81 pvfs->search.inactivity_time = share_int_option(scfg,
82 PVFS_SEARCH_INACTIVITY,
83 PVFS_SEARCH_INACTIVITY_DEFAULT);
85 #if HAVE_XATTR_SUPPORT
86 if (share_bool_option(scfg, PVFS_XATTR, PVFS_XATTR_DEFAULT))
87 pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
90 pvfs->sharing_violation_delay = share_int_option(scfg,
92 PVFS_SHARE_DELAY_DEFAULT);
94 pvfs->share_name = talloc_strdup(pvfs, scfg->name);
97 FS_ATTR_CASE_SENSITIVE_SEARCH |
98 FS_ATTR_CASE_PRESERVED_NAMES |
99 FS_ATTR_UNICODE_ON_DISK |
100 FS_ATTR_SPARSE_FILES;
102 /* allow xattrs to be stored in a external tdb */
103 eadb = share_string_option(scfg, PVFS_EADB, NULL);
105 pvfs->ea_db = tdb_wrap_open(pvfs, eadb, 50000,
106 TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
107 if (pvfs->ea_db != NULL) {
108 pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
110 DEBUG(0,("Failed to open eadb '%s' - %s\n",
111 eadb, strerror(errno)));
112 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
116 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
117 pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS;
119 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
120 pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS;
123 pvfs->sid_cache.creator_owner = dom_sid_parse_talloc(pvfs, SID_CREATOR_OWNER);
124 pvfs->sid_cache.creator_group = dom_sid_parse_talloc(pvfs, SID_CREATOR_GROUP);
126 /* check if the system really supports xattrs */
127 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
128 pvfs_xattr_probe(pvfs);
131 /* enable an ACL backend */
132 pvfs->acl_ops = pvfs_acl_backend_byname(share_string_option(scfg, PVFS_ACL, "xattr"));
135 static int pvfs_state_destructor(struct pvfs_state *pvfs)
137 struct pvfs_file *f, *fn;
138 struct pvfs_search_state *s, *sn;
141 * make sure we cleanup files and searches before anything else
142 * because there destructors need to acess the pvfs_state struct
144 for (f=pvfs->files.list; f; f=fn) {
149 for (s=pvfs->search.list; s; s=sn) {
158 connect to a share - used when a tree_connect operation comes
159 in. For a disk based backend we needs to ensure that the base
160 directory exists (tho it doesn't need to be accessible by the user,
163 static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
164 struct ntvfs_request *req, const char *sharename)
166 struct pvfs_state *pvfs;
168 char *base_directory;
171 pvfs = talloc_zero(ntvfs, struct pvfs_state);
172 NT_STATUS_HAVE_NO_MEMORY(pvfs);
174 /* for simplicity of path construction, remove any trailing slash now */
175 base_directory = talloc_strdup(pvfs, share_string_option(ntvfs->ctx->config, SHARE_PATH, ""));
176 NT_STATUS_HAVE_NO_MEMORY(base_directory);
177 if (strcmp(base_directory, "/") != 0) {
178 trim_string(base_directory, NULL, "/");
182 pvfs->base_directory = base_directory;
184 /* the directory must exist. Note that we deliberately don't
185 check that it is readable */
186 if (stat(pvfs->base_directory, &st) != 0 || !S_ISDIR(st.st_mode)) {
187 DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n",
188 pvfs->base_directory, sharename));
189 return NT_STATUS_BAD_NETWORK_NAME;
192 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
193 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
195 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
196 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
198 ntvfs->private_data = pvfs;
200 pvfs->brl_context = brl_init(pvfs,
201 pvfs->ntvfs->ctx->server_id,
202 pvfs->ntvfs->ctx->msg_ctx);
203 if (pvfs->brl_context == NULL) {
204 return NT_STATUS_INTERNAL_DB_CORRUPTION;
207 pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx);
208 if (pvfs->odb_context == NULL) {
209 return NT_STATUS_INTERNAL_DB_CORRUPTION;
212 /* allow this to be NULL - we just disable change notify */
213 pvfs->notify_context = notify_init(pvfs,
214 pvfs->ntvfs->ctx->server_id,
215 pvfs->ntvfs->ctx->msg_ctx,
216 event_context_find(pvfs),
217 pvfs->ntvfs->ctx->config);
219 pvfs->sidmap = sidmap_open(pvfs);
220 if (pvfs->sidmap == NULL) {
221 return NT_STATUS_INTERNAL_DB_CORRUPTION;
224 /* allocate the search handle -> ptr tree */
225 pvfs->search.idtree = idr_init(pvfs);
226 NT_STATUS_HAVE_NO_MEMORY(pvfs->search.idtree);
228 status = pvfs_mangle_init(pvfs);
229 NT_STATUS_NOT_OK_RETURN(status);
231 pvfs_setup_options(pvfs);
233 talloc_set_destructor(pvfs, pvfs_state_destructor);
236 /* who had the stupid idea to generate a signal on a large
237 file write instead of just failing it!? */
238 BlockSignals(True, SIGXFSZ);
245 disconnect from a share
247 static NTSTATUS pvfs_disconnect(struct ntvfs_module_context *ntvfs)
253 check if a directory exists
255 static NTSTATUS pvfs_chkpath(struct ntvfs_module_context *ntvfs,
256 struct ntvfs_request *req,
257 union smb_chkpath *cp)
259 struct pvfs_state *pvfs = ntvfs->private_data;
260 struct pvfs_filename *name;
263 /* resolve the cifs name to a posix name */
264 status = pvfs_resolve_name(pvfs, req, cp->chkpath.in.path, 0, &name);
265 NT_STATUS_NOT_OK_RETURN(status);
268 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
271 if (!S_ISDIR(name->st.st_mode)) {
272 return NT_STATUS_NOT_A_DIRECTORY;
281 static NTSTATUS pvfs_copy(struct ntvfs_module_context *ntvfs,
282 struct ntvfs_request *req, struct smb_copy *cp)
284 DEBUG(0,("pvfs_copy not implemented\n"));
285 return NT_STATUS_NOT_SUPPORTED;
289 return print queue info
291 static NTSTATUS pvfs_lpq(struct ntvfs_module_context *ntvfs,
292 struct ntvfs_request *req, union smb_lpq *lpq)
294 return NT_STATUS_NOT_SUPPORTED;
297 /* SMBtrans - not used on file shares */
298 static NTSTATUS pvfs_trans(struct ntvfs_module_context *ntvfs,
299 struct ntvfs_request *req, struct smb_trans2 *trans2)
301 return NT_STATUS_ACCESS_DENIED;
305 initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
307 NTSTATUS ntvfs_posix_init(void)
310 struct ntvfs_ops ops;
311 NTVFS_CURRENT_CRITICAL_SIZES(vers);
315 ops.type = NTVFS_DISK;
317 /* fill in all the operations */
318 ops.connect = pvfs_connect;
319 ops.disconnect = pvfs_disconnect;
320 ops.unlink = pvfs_unlink;
321 ops.chkpath = pvfs_chkpath;
322 ops.qpathinfo = pvfs_qpathinfo;
323 ops.setpathinfo = pvfs_setpathinfo;
324 ops.open = pvfs_open;
325 ops.mkdir = pvfs_mkdir;
326 ops.rmdir = pvfs_rmdir;
327 ops.rename = pvfs_rename;
328 ops.copy = pvfs_copy;
329 ops.ioctl = pvfs_ioctl;
330 ops.read = pvfs_read;
331 ops.write = pvfs_write;
332 ops.seek = pvfs_seek;
333 ops.flush = pvfs_flush;
334 ops.close = pvfs_close;
335 ops.exit = pvfs_exit;
336 ops.lock = pvfs_lock;
337 ops.setfileinfo = pvfs_setfileinfo;
338 ops.qfileinfo = pvfs_qfileinfo;
339 ops.fsinfo = pvfs_fsinfo;
341 ops.search_first = pvfs_search_first;
342 ops.search_next = pvfs_search_next;
343 ops.search_close = pvfs_search_close;
344 ops.trans = pvfs_trans;
345 ops.logoff = pvfs_logoff;
346 ops.async_setup = pvfs_async_setup;
347 ops.cancel = pvfs_cancel;
348 ops.notify = pvfs_notify;
350 /* register ourselves with the NTVFS subsystem. We register
351 under the name 'default' as we wish to be the default
352 backend, and also register as 'posix' */
353 ops.name = "default";
354 ret = ntvfs_register(&ops, &vers);
356 if (!NT_STATUS_IS_OK(ret)) {
357 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
361 ret = ntvfs_register(&ops, &vers);
363 if (!NT_STATUS_IS_OK(ret)) {
364 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
367 if (NT_STATUS_IS_OK(ret)) {
368 ret = ntvfs_common_init();