s3:nmbd: add _NMBD_NMBD_H_ guard to nmbd.h
[Samba/gebeck_regimport.git] / source4 / ntvfs / posix / vfs_posix.c
blob4c1404eec578ff120dc67fd07a29b1a798aa3acc
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.h>
30 #include "lib/util/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 const char *eadb;
42 bool def_perm_override = false;
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 #if defined(O_DIRECTORY) && defined(O_NOFOLLOW)
64 /* set PVFS_PERM_OVERRIDE by default only if the system
65 * supports the necessary capabilities to make it secure
67 def_perm_override = true;
68 #endif
69 if (share_bool_option(scfg, PVFS_PERM_OVERRIDE, def_perm_override))
70 pvfs->flags |= PVFS_FLAG_PERM_OVERRIDE;
72 /* file perm options */
73 pvfs->options.create_mask = share_int_option(scfg,
74 SHARE_CREATE_MASK,
75 SHARE_CREATE_MASK_DEFAULT);
76 pvfs->options.dir_mask = share_int_option(scfg,
77 SHARE_DIR_MASK,
78 SHARE_DIR_MASK_DEFAULT);
79 pvfs->options.force_dir_mode = share_int_option(scfg,
80 SHARE_FORCE_DIR_MODE,
81 SHARE_FORCE_DIR_MODE_DEFAULT);
82 pvfs->options.force_create_mode = share_int_option(scfg,
83 SHARE_FORCE_CREATE_MODE,
84 SHARE_FORCE_CREATE_MODE_DEFAULT);
85 /* this must be a power of 2 */
86 pvfs->alloc_size_rounding = share_int_option(scfg,
87 PVFS_ALLOCATION_ROUNDING,
88 PVFS_ALLOCATION_ROUNDING_DEFAULT);
90 pvfs->search.inactivity_time = share_int_option(scfg,
91 PVFS_SEARCH_INACTIVITY,
92 PVFS_SEARCH_INACTIVITY_DEFAULT);
94 #if HAVE_XATTR_SUPPORT
95 if (share_bool_option(scfg, PVFS_XATTR, PVFS_XATTR_DEFAULT))
96 pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
97 #endif
99 pvfs->sharing_violation_delay = share_int_option(scfg,
100 PVFS_SHARE_DELAY,
101 PVFS_SHARE_DELAY_DEFAULT);
103 pvfs->oplock_break_timeout = share_int_option(scfg,
104 PVFS_OPLOCK_TIMEOUT,
105 PVFS_OPLOCK_TIMEOUT_DEFAULT);
107 pvfs->writetime_delay = share_int_option(scfg,
108 PVFS_WRITETIME_DELAY,
109 PVFS_WRITETIME_DELAY_DEFAULT);
111 pvfs->share_name = talloc_strdup(pvfs, scfg->name);
113 pvfs->fs_attribs =
114 FS_ATTR_CASE_SENSITIVE_SEARCH |
115 FS_ATTR_CASE_PRESERVED_NAMES |
116 FS_ATTR_UNICODE_ON_DISK |
117 FS_ATTR_SPARSE_FILES;
119 /* allow xattrs to be stored in a external tdb */
120 eadb = share_string_option(scfg, PVFS_EADB, NULL);
121 if (eadb != NULL) {
122 pvfs->ea_db = tdb_wrap_open(pvfs, eadb, 50000,
123 TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
124 if (pvfs->ea_db != NULL) {
125 pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
126 } else {
127 DEBUG(0,("Failed to open eadb '%s' - %s\n",
128 eadb, strerror(errno)));
129 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
133 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
134 pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS;
136 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
137 pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS;
140 pvfs->sid_cache.creator_owner = dom_sid_parse_talloc(pvfs, SID_CREATOR_OWNER);
141 pvfs->sid_cache.creator_group = dom_sid_parse_talloc(pvfs, SID_CREATOR_GROUP);
143 /* check if the system really supports xattrs */
144 if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
145 pvfs_xattr_probe(pvfs);
148 /* enable an ACL backend */
149 pvfs->acl_ops = pvfs_acl_backend_byname(share_string_option(scfg, PVFS_ACL, "xattr"));
152 static int pvfs_state_destructor(struct pvfs_state *pvfs)
154 struct pvfs_file *f, *fn;
155 struct pvfs_search_state *s, *sn;
158 * make sure we cleanup files and searches before anything else
159 * because there destructors need to acess the pvfs_state struct
161 for (f=pvfs->files.list; f; f=fn) {
162 fn = f->next;
163 talloc_free(f);
166 for (s=pvfs->search.list; s; s=sn) {
167 sn = s->next;
168 talloc_free(s);
171 return 0;
175 connect to a share - used when a tree_connect operation comes
176 in. For a disk based backend we needs to ensure that the base
177 directory exists (tho it doesn't need to be accessible by the user,
178 that comes later)
180 static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
181 struct ntvfs_request *req,
182 union smb_tcon* tcon)
184 struct pvfs_state *pvfs;
185 struct stat st;
186 char *base_directory;
187 NTSTATUS status;
188 const char *sharename;
190 switch (tcon->generic.level) {
191 case RAW_TCON_TCON:
192 sharename = tcon->tcon.in.service;
193 break;
194 case RAW_TCON_TCONX:
195 sharename = tcon->tconx.in.path;
196 break;
197 case RAW_TCON_SMB2:
198 sharename = tcon->smb2.in.path;
199 break;
200 default:
201 return NT_STATUS_INVALID_LEVEL;
204 if (strncmp(sharename, "\\\\", 2) == 0) {
205 char *p = strchr(sharename+2, '\\');
206 if (p) {
207 sharename = p + 1;
212 * TODO: call this from ntvfs_posix_init()
213 * but currently we don't have a lp_ctx there
215 status = pvfs_acl_init(ntvfs->ctx->lp_ctx);
216 NT_STATUS_NOT_OK_RETURN(status);
218 pvfs = talloc_zero(ntvfs, struct pvfs_state);
219 NT_STATUS_HAVE_NO_MEMORY(pvfs);
221 /* for simplicity of path construction, remove any trailing slash now */
222 base_directory = talloc_strdup(pvfs, share_string_option(ntvfs->ctx->config, SHARE_PATH, ""));
223 NT_STATUS_HAVE_NO_MEMORY(base_directory);
224 if (strcmp(base_directory, "/") != 0) {
225 trim_string(base_directory, NULL, "/");
228 pvfs->ntvfs = ntvfs;
229 pvfs->base_directory = base_directory;
231 /* the directory must exist. Note that we deliberately don't
232 check that it is readable */
233 if (stat(pvfs->base_directory, &st) != 0 || !S_ISDIR(st.st_mode)) {
234 DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n",
235 pvfs->base_directory, sharename));
236 return NT_STATUS_BAD_NETWORK_NAME;
239 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
240 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
242 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
243 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
245 if (tcon->generic.level == RAW_TCON_TCONX) {
246 tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
247 tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
250 ntvfs->private_data = pvfs;
252 pvfs->brl_context = brlock_init(pvfs,
253 pvfs->ntvfs->ctx->server_id,
254 pvfs->ntvfs->ctx->lp_ctx,
255 pvfs->ntvfs->ctx->msg_ctx);
256 if (pvfs->brl_context == NULL) {
257 return NT_STATUS_INTERNAL_DB_CORRUPTION;
260 pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx);
261 if (pvfs->odb_context == NULL) {
262 return NT_STATUS_INTERNAL_DB_CORRUPTION;
265 /* allow this to be NULL - we just disable change notify */
266 pvfs->notify_context = notify_init(pvfs,
267 pvfs->ntvfs->ctx->server_id,
268 pvfs->ntvfs->ctx->msg_ctx,
269 pvfs->ntvfs->ctx->lp_ctx,
270 pvfs->ntvfs->ctx->event_ctx,
271 pvfs->ntvfs->ctx->config);
273 pvfs->wbc_ctx = wbc_init(pvfs,
274 pvfs->ntvfs->ctx->msg_ctx,
275 pvfs->ntvfs->ctx->event_ctx);
276 if (pvfs->wbc_ctx == NULL) {
277 return NT_STATUS_INTERNAL_DB_CORRUPTION;
280 /* allocate the search handle -> ptr tree */
281 pvfs->search.idtree = idr_init(pvfs);
282 NT_STATUS_HAVE_NO_MEMORY(pvfs->search.idtree);
284 status = pvfs_mangle_init(pvfs);
285 NT_STATUS_NOT_OK_RETURN(status);
287 pvfs_setup_options(pvfs);
289 talloc_set_destructor(pvfs, pvfs_state_destructor);
291 #ifdef SIGXFSZ
292 /* who had the stupid idea to generate a signal on a large
293 file write instead of just failing it!? */
294 BlockSignals(true, SIGXFSZ);
295 #endif
297 return NT_STATUS_OK;
301 disconnect from a share
303 static NTSTATUS pvfs_disconnect(struct ntvfs_module_context *ntvfs)
305 return NT_STATUS_OK;
309 check if a directory exists
311 static NTSTATUS pvfs_chkpath(struct ntvfs_module_context *ntvfs,
312 struct ntvfs_request *req,
313 union smb_chkpath *cp)
315 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
316 struct pvfs_state);
317 struct pvfs_filename *name;
318 NTSTATUS status;
320 /* resolve the cifs name to a posix name */
321 status = pvfs_resolve_name(pvfs, req, cp->chkpath.in.path, 0, &name);
322 NT_STATUS_NOT_OK_RETURN(status);
324 if (!name->exists) {
325 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
328 if (!S_ISDIR(name->st.st_mode)) {
329 return NT_STATUS_NOT_A_DIRECTORY;
332 return NT_STATUS_OK;
336 copy a set of files
338 static NTSTATUS pvfs_copy(struct ntvfs_module_context *ntvfs,
339 struct ntvfs_request *req, struct smb_copy *cp)
341 DEBUG(0,("pvfs_copy not implemented\n"));
342 return NT_STATUS_NOT_SUPPORTED;
346 return print queue info
348 static NTSTATUS pvfs_lpq(struct ntvfs_module_context *ntvfs,
349 struct ntvfs_request *req, union smb_lpq *lpq)
351 return NT_STATUS_NOT_SUPPORTED;
354 /* SMBtrans - not used on file shares */
355 static NTSTATUS pvfs_trans(struct ntvfs_module_context *ntvfs,
356 struct ntvfs_request *req, struct smb_trans2 *trans2)
358 return NT_STATUS_ACCESS_DENIED;
362 initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
364 NTSTATUS ntvfs_posix_init(void)
366 NTSTATUS ret;
367 struct ntvfs_ops ops;
368 NTVFS_CURRENT_CRITICAL_SIZES(vers);
370 ZERO_STRUCT(ops);
372 ops.type = NTVFS_DISK;
374 /* fill in all the operations */
375 ops.connect = pvfs_connect;
376 ops.disconnect = pvfs_disconnect;
377 ops.unlink = pvfs_unlink;
378 ops.chkpath = pvfs_chkpath;
379 ops.qpathinfo = pvfs_qpathinfo;
380 ops.setpathinfo = pvfs_setpathinfo;
381 ops.open = pvfs_open;
382 ops.mkdir = pvfs_mkdir;
383 ops.rmdir = pvfs_rmdir;
384 ops.rename = pvfs_rename;
385 ops.copy = pvfs_copy;
386 ops.ioctl = pvfs_ioctl;
387 ops.read = pvfs_read;
388 ops.write = pvfs_write;
389 ops.seek = pvfs_seek;
390 ops.flush = pvfs_flush;
391 ops.close = pvfs_close;
392 ops.exit = pvfs_exit;
393 ops.lock = pvfs_lock;
394 ops.setfileinfo = pvfs_setfileinfo;
395 ops.qfileinfo = pvfs_qfileinfo;
396 ops.fsinfo = pvfs_fsinfo;
397 ops.lpq = pvfs_lpq;
398 ops.search_first = pvfs_search_first;
399 ops.search_next = pvfs_search_next;
400 ops.search_close = pvfs_search_close;
401 ops.trans = pvfs_trans;
402 ops.logoff = pvfs_logoff;
403 ops.async_setup = pvfs_async_setup;
404 ops.cancel = pvfs_cancel;
405 ops.notify = pvfs_notify;
407 /* register ourselves with the NTVFS subsystem. We register
408 under the name 'default' as we wish to be the default
409 backend, and also register as 'posix' */
410 ops.name = "default";
411 ret = ntvfs_register(&ops, &vers);
413 if (!NT_STATUS_IS_OK(ret)) {
414 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
417 ops.name = "posix";
418 ret = ntvfs_register(&ops, &vers);
420 if (!NT_STATUS_IS_OK(ret)) {
421 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
424 if (NT_STATUS_IS_OK(ret)) {
425 ret = ntvfs_common_init();
428 return ret;