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 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
27 #include "vfs_posix.h"
28 #include "librpc/gen_ndr/security.h"
29 #include "tdb_compat.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
;
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;
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
,
75 SHARE_CREATE_MASK_DEFAULT
);
76 pvfs
->options
.dir_mask
= share_int_option(scfg
,
78 SHARE_DIR_MASK_DEFAULT
);
79 pvfs
->options
.force_dir_mode
= share_int_option(scfg
,
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
;
99 pvfs
->sharing_violation_delay
= share_int_option(scfg
,
101 PVFS_SHARE_DELAY_DEFAULT
);
103 pvfs
->oplock_break_timeout
= share_int_option(scfg
,
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
);
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
);
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
;
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
) {
166 for (s
=pvfs
->search
.list
; s
; s
=sn
) {
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,
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
;
186 char *base_directory
;
188 const char *sharename
;
190 switch (tcon
->generic
.level
) {
192 sharename
= tcon
->tcon
.in
.service
;
195 sharename
= tcon
->tconx
.in
.path
;
198 sharename
= tcon
->smb2
.in
.path
;
201 return NT_STATUS_INVALID_LEVEL
;
204 if (strncmp(sharename
, "\\\\", 2) == 0) {
205 char *p
= strchr(sharename
+2, '\\');
212 * TODO: call this from ntvfs_posix_init()
213 * but currently we don't have a lp_ctx there
215 status
= pvfs_acl_init();
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
, "/");
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
);
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
);
301 disconnect from a share
303 static NTSTATUS
pvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
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
,
317 struct pvfs_filename
*name
;
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
);
325 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
328 if (!S_ISDIR(name
->st
.st_mode
)) {
329 return NT_STATUS_NOT_A_DIRECTORY
;
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)
367 struct ntvfs_ops ops
;
368 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
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
;
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
));
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();