smbd: Remove superfluous ()
[Samba.git] / source4 / ntvfs / posix / vfs_posix.c
blob304a9ff8fe58063c12c69c93079fac417dd28fb9
1 /*
2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend
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 3 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, see <http://www.gnu.org/licenses/>.
22 this implements most of the POSIX NTVFS backend
23 This is the default backend
26 #include "includes.h"
27 #include "vfs_posix.h"
28 #include "librpc/gen_ndr/security.h"
29 #include "tdb_compat.h"
30 #include "lib/tdb_wrap/tdb_wrap.h"
31 #include "libcli/security/security.h"
32 #include "lib/events/events.h"
33 #include "param/param.h"
36 setup config options for a posix share
38 static void pvfs_setup_options(struct pvfs_state *pvfs)
40 struct share_config *scfg = pvfs->ntvfs->ctx->config;
41 char *eadb;
42 char *xattr_backend;
43 bool def_perm_override = false;
45 if (share_bool_option(scfg, SHARE_MAP_HIDDEN, SHARE_MAP_HIDDEN_DEFAULT))
46 pvfs->flags |= PVFS_FLAG_MAP_HIDDEN;
47 if (share_bool_option(scfg, SHARE_MAP_ARCHIVE, SHARE_MAP_ARCHIVE_DEFAULT))
48 pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE;
49 if (share_bool_option(scfg, SHARE_MAP_SYSTEM, SHARE_MAP_SYSTEM_DEFAULT))
50 pvfs->flags |= PVFS_FLAG_MAP_SYSTEM;
51 if (share_bool_option(scfg, SHARE_READONLY, SHARE_READONLY_DEFAULT))
52 pvfs->flags |= PVFS_FLAG_READONLY;
53 if (share_bool_option(scfg, SHARE_STRICT_SYNC, SHARE_STRICT_SYNC_DEFAULT))
54 pvfs->flags |= PVFS_FLAG_STRICT_SYNC;
55 if (share_bool_option(scfg, SHARE_STRICT_LOCKING, SHARE_STRICT_LOCKING_DEFAULT))
56 pvfs->flags |= PVFS_FLAG_STRICT_LOCKING;
57 if (share_bool_option(scfg, SHARE_CI_FILESYSTEM, SHARE_CI_FILESYSTEM_DEFAULT))
58 pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM;
59 if (share_bool_option(scfg, PVFS_FAKE_OPLOCKS, PVFS_FAKE_OPLOCKS_DEFAULT))
60 pvfs->flags |= PVFS_FLAG_FAKE_OPLOCKS;
61 if (share_bool_option(scfg, PVFS_AIO, false))
62 pvfs->flags |= PVFS_FLAG_LINUX_AIO;
64 #if defined(O_DIRECTORY) && defined(O_NOFOLLOW)
65 /* set PVFS_PERM_OVERRIDE by default only if the system
66 * supports the necessary capabilities to make it secure
68 def_perm_override = true;
69 #endif
70 if (share_bool_option(scfg, PVFS_PERM_OVERRIDE, def_perm_override))
71 pvfs->flags |= PVFS_FLAG_PERM_OVERRIDE;
73 /* file perm options */
74 pvfs->options.create_mask = share_int_option(scfg,
75 SHARE_CREATE_MASK,
76 SHARE_CREATE_MASK_DEFAULT);
77 pvfs->options.dir_mask = share_int_option(scfg,
78 SHARE_DIR_MASK,
79 SHARE_DIR_MASK_DEFAULT);
80 pvfs->options.force_dir_mode = share_int_option(scfg,
81 SHARE_FORCE_DIR_MODE,
82 SHARE_FORCE_DIR_MODE_DEFAULT);
83 pvfs->options.force_create_mode = share_int_option(scfg,
84 SHARE_FORCE_CREATE_MODE,
85 SHARE_FORCE_CREATE_MODE_DEFAULT);
86 /* this must be a power of 2 */
87 pvfs->alloc_size_rounding = share_int_option(scfg,
88 PVFS_ALLOCATION_ROUNDING,
89 PVFS_ALLOCATION_ROUNDING_DEFAULT);
91 pvfs->search.inactivity_time = share_int_option(scfg,
92 PVFS_SEARCH_INACTIVITY,
93 PVFS_SEARCH_INACTIVITY_DEFAULT);
95 #if HAVE_XATTR_SUPPORT
96 if (share_bool_option(scfg, PVFS_XATTR, PVFS_XATTR_DEFAULT))
97 pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
98 #endif
100 pvfs->sharing_violation_delay = share_int_option(scfg,
101 PVFS_SHARE_DELAY,
102 PVFS_SHARE_DELAY_DEFAULT);
104 pvfs->oplock_break_timeout = share_int_option(scfg,
105 PVFS_OPLOCK_TIMEOUT,
106 PVFS_OPLOCK_TIMEOUT_DEFAULT);
108 pvfs->writetime_delay = share_int_option(scfg,
109 PVFS_WRITETIME_DELAY,
110 PVFS_WRITETIME_DELAY_DEFAULT);
112 pvfs->share_name = talloc_strdup(pvfs, scfg->name);
114 pvfs->fs_attribs =
115 FS_ATTR_CASE_SENSITIVE_SEARCH |
116 FS_ATTR_CASE_PRESERVED_NAMES |
117 FS_ATTR_UNICODE_ON_DISK |
118 FS_ATTR_SPARSE_FILES;
120 /* allow xattrs to be stored in a external tdb */
121 eadb = share_string_option(pvfs, scfg, PVFS_EADB, NULL);
122 if (eadb != NULL) {
123 pvfs->ea_db = tdb_wrap_open(
124 pvfs, eadb, 50000,
125 lpcfg_tdb_flags(pvfs->ntvfs->ctx->lp_ctx, TDB_DEFAULT),
126 O_RDWR|O_CREAT, 0600);
127 TALLOC_FREE(eadb);
128 if (pvfs->ea_db != NULL) {
129 pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
130 } else {
131 DEBUG(0,("Failed to open eadb '%s' - %s\n",
132 eadb, strerror(errno)));
133 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
137 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
138 pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS;
140 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
141 pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS;
144 pvfs->sid_cache.creator_owner = dom_sid_parse_talloc(pvfs, SID_CREATOR_OWNER);
145 pvfs->sid_cache.creator_group = dom_sid_parse_talloc(pvfs, SID_CREATOR_GROUP);
147 /* check if the system really supports xattrs */
148 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
149 pvfs_xattr_probe(pvfs);
152 /* enable an ACL backend */
153 xattr_backend = share_string_option(pvfs, scfg, PVFS_ACL, "xattr");
154 pvfs->acl_ops = pvfs_acl_backend_byname(xattr_backend);
155 TALLOC_FREE(xattr_backend);
158 static int pvfs_state_destructor(struct pvfs_state *pvfs)
160 struct pvfs_file *f, *fn;
161 struct pvfs_search_state *s, *sn;
164 * make sure we cleanup files and searches before anything else
165 * because there destructors need to acess the pvfs_state struct
167 for (f=pvfs->files.list; f; f=fn) {
168 fn = f->next;
169 talloc_free(f);
172 for (s=pvfs->search.list; s; s=sn) {
173 sn = s->next;
174 talloc_free(s);
177 return 0;
181 connect to a share - used when a tree_connect operation comes
182 in. For a disk based backend we needs to ensure that the base
183 directory exists (tho it doesn't need to be accessible by the user,
184 that comes later)
186 static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
187 struct ntvfs_request *req,
188 union smb_tcon* tcon)
190 struct pvfs_state *pvfs;
191 struct stat st;
192 char *base_directory;
193 NTSTATUS status;
194 const char *sharename;
196 switch (tcon->generic.level) {
197 case RAW_TCON_TCON:
198 sharename = tcon->tcon.in.service;
199 break;
200 case RAW_TCON_TCONX:
201 sharename = tcon->tconx.in.path;
202 break;
203 case RAW_TCON_SMB2:
204 sharename = tcon->smb2.in.path;
205 break;
206 default:
207 return NT_STATUS_INVALID_LEVEL;
210 if (strncmp(sharename, "\\\\", 2) == 0) {
211 char *p = strchr(sharename+2, '\\');
212 if (p) {
213 sharename = p + 1;
218 * TODO: call this from ntvfs_posix_init()
219 * but currently we don't have a lp_ctx there
221 status = pvfs_acl_init();
222 NT_STATUS_NOT_OK_RETURN(status);
224 pvfs = talloc_zero(ntvfs, struct pvfs_state);
225 NT_STATUS_HAVE_NO_MEMORY(pvfs);
227 /* for simplicity of path construction, remove any trailing slash now */
228 base_directory = share_string_option(pvfs, ntvfs->ctx->config, SHARE_PATH, "");
229 NT_STATUS_HAVE_NO_MEMORY(base_directory);
230 if (strcmp(base_directory, "/") != 0) {
231 trim_string(base_directory, NULL, "/");
234 pvfs->ntvfs = ntvfs;
235 pvfs->base_directory = base_directory;
237 /* the directory must exist. Note that we deliberately don't
238 check that it is readable */
239 if (stat(pvfs->base_directory, &st) != 0 || !S_ISDIR(st.st_mode)) {
240 DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n",
241 pvfs->base_directory, sharename));
242 return NT_STATUS_BAD_NETWORK_NAME;
245 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
246 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
248 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
249 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
251 if (tcon->generic.level == RAW_TCON_TCONX) {
252 tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
253 tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
256 ntvfs->private_data = pvfs;
258 pvfs->brl_context = brlock_init(pvfs,
259 pvfs->ntvfs->ctx->server_id,
260 pvfs->ntvfs->ctx->lp_ctx,
261 pvfs->ntvfs->ctx->msg_ctx);
262 if (pvfs->brl_context == NULL) {
263 return NT_STATUS_INTERNAL_DB_CORRUPTION;
266 pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx);
267 if (pvfs->odb_context == NULL) {
268 return NT_STATUS_INTERNAL_DB_CORRUPTION;
271 /* allow this to be NULL - we just disable change notify */
272 pvfs->notify_context = notify_init(pvfs,
273 pvfs->ntvfs->ctx->server_id,
274 pvfs->ntvfs->ctx->msg_ctx,
275 pvfs->ntvfs->ctx->lp_ctx,
276 pvfs->ntvfs->ctx->event_ctx,
277 pvfs->ntvfs->ctx->config);
279 /* allocate the search handle -> ptr tree */
280 pvfs->search.idtree = idr_init(pvfs);
281 NT_STATUS_HAVE_NO_MEMORY(pvfs->search.idtree);
283 status = pvfs_mangle_init(pvfs);
284 NT_STATUS_NOT_OK_RETURN(status);
286 pvfs_setup_options(pvfs);
288 talloc_set_destructor(pvfs, pvfs_state_destructor);
290 #ifdef SIGXFSZ
291 /* who had the stupid idea to generate a signal on a large
292 file write instead of just failing it!? */
293 BlockSignals(true, SIGXFSZ);
294 #endif
296 return NT_STATUS_OK;
300 disconnect from a share
302 static NTSTATUS pvfs_disconnect(struct ntvfs_module_context *ntvfs)
304 return NT_STATUS_OK;
308 check if a directory exists
310 static NTSTATUS pvfs_chkpath(struct ntvfs_module_context *ntvfs,
311 struct ntvfs_request *req,
312 union smb_chkpath *cp)
314 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
315 struct pvfs_state);
316 struct pvfs_filename *name;
317 NTSTATUS status;
319 /* resolve the cifs name to a posix name */
320 status = pvfs_resolve_name(pvfs, req, cp->chkpath.in.path, 0, &name);
321 NT_STATUS_NOT_OK_RETURN(status);
323 if (!name->exists) {
324 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
327 if (!S_ISDIR(name->st.st_mode)) {
328 return NT_STATUS_NOT_A_DIRECTORY;
331 return NT_STATUS_OK;
335 copy a set of files
337 static NTSTATUS pvfs_copy(struct ntvfs_module_context *ntvfs,
338 struct ntvfs_request *req, struct smb_copy *cp)
340 DEBUG(0,("pvfs_copy not implemented\n"));
341 return NT_STATUS_NOT_SUPPORTED;
345 return print queue info
347 static NTSTATUS pvfs_lpq(struct ntvfs_module_context *ntvfs,
348 struct ntvfs_request *req, union smb_lpq *lpq)
350 return NT_STATUS_NOT_SUPPORTED;
353 /* SMBtrans - not used on file shares */
354 static NTSTATUS pvfs_trans(struct ntvfs_module_context *ntvfs,
355 struct ntvfs_request *req, struct smb_trans2 *trans2)
357 return NT_STATUS_ACCESS_DENIED;
361 initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
363 NTSTATUS ntvfs_posix_init(void)
365 NTSTATUS ret;
366 struct ntvfs_ops ops;
367 NTVFS_CURRENT_CRITICAL_SIZES(vers);
369 ZERO_STRUCT(ops);
371 ops.type = NTVFS_DISK;
373 /* fill in all the operations */
374 ops.connect_fn = pvfs_connect;
375 ops.disconnect_fn = pvfs_disconnect;
376 ops.unlink_fn = pvfs_unlink;
377 ops.chkpath_fn = pvfs_chkpath;
378 ops.qpathinfo_fn = pvfs_qpathinfo;
379 ops.setpathinfo_fn = pvfs_setpathinfo;
380 ops.open_fn = pvfs_open;
381 ops.mkdir_fn = pvfs_mkdir;
382 ops.rmdir_fn = pvfs_rmdir;
383 ops.rename_fn = pvfs_rename;
384 ops.copy_fn = pvfs_copy;
385 ops.ioctl_fn = pvfs_ioctl;
386 ops.read_fn = pvfs_read;
387 ops.write_fn = pvfs_write;
388 ops.seek_fn = pvfs_seek;
389 ops.flush_fn = pvfs_flush;
390 ops.close_fn = pvfs_close;
391 ops.exit_fn = pvfs_exit;
392 ops.lock_fn = pvfs_lock;
393 ops.setfileinfo_fn = pvfs_setfileinfo;
394 ops.qfileinfo_fn = pvfs_qfileinfo;
395 ops.fsinfo_fn = pvfs_fsinfo;
396 ops.lpq_fn = pvfs_lpq;
397 ops.search_first_fn = pvfs_search_first;
398 ops.search_next_fn = pvfs_search_next;
399 ops.search_close_fn = pvfs_search_close;
400 ops.trans_fn = pvfs_trans;
401 ops.logoff_fn = pvfs_logoff;
402 ops.async_setup_fn = pvfs_async_setup;
403 ops.cancel_fn = pvfs_cancel;
404 ops.notify_fn = pvfs_notify;
406 /* register ourselves with the NTVFS subsystem. We register
407 under the name 'default' as we wish to be the default
408 backend, and also register as 'posix' */
409 ops.name = "default";
410 ret = ntvfs_register(&ops, &vers);
412 if (!NT_STATUS_IS_OK(ret)) {
413 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
416 ops.name = "posix";
417 ret = ntvfs_register(&ops, &vers);
419 if (!NT_STATUS_IS_OK(ret)) {
420 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
423 if (NT_STATUS_IS_OK(ret)) {
424 ret = ntvfs_common_init();
427 return ret;