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/include/tdb.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
;
43 if (share_bool_option(scfg
, SHARE_MAP_HIDDEN
, SHARE_MAP_HIDDEN_DEFAULT
))
44 pvfs
->flags
|= PVFS_FLAG_MAP_HIDDEN
;
45 if (share_bool_option(scfg
, SHARE_MAP_ARCHIVE
, SHARE_MAP_ARCHIVE_DEFAULT
))
46 pvfs
->flags
|= PVFS_FLAG_MAP_ARCHIVE
;
47 if (share_bool_option(scfg
, SHARE_MAP_SYSTEM
, SHARE_MAP_SYSTEM_DEFAULT
))
48 pvfs
->flags
|= PVFS_FLAG_MAP_SYSTEM
;
49 if (share_bool_option(scfg
, SHARE_READONLY
, SHARE_READONLY_DEFAULT
))
50 pvfs
->flags
|= PVFS_FLAG_READONLY
;
51 if (share_bool_option(scfg
, SHARE_STRICT_SYNC
, SHARE_STRICT_SYNC_DEFAULT
))
52 pvfs
->flags
|= PVFS_FLAG_STRICT_SYNC
;
53 if (share_bool_option(scfg
, SHARE_STRICT_LOCKING
, SHARE_STRICT_LOCKING_DEFAULT
))
54 pvfs
->flags
|= PVFS_FLAG_STRICT_LOCKING
;
55 if (share_bool_option(scfg
, SHARE_CI_FILESYSTEM
, SHARE_CI_FILESYSTEM_DEFAULT
))
56 pvfs
->flags
|= PVFS_FLAG_CI_FILESYSTEM
;
57 if (share_bool_option(scfg
, PVFS_FAKE_OPLOCKS
, PVFS_FAKE_OPLOCKS_DEFAULT
))
58 pvfs
->flags
|= PVFS_FLAG_FAKE_OPLOCKS
;
59 if (share_bool_option(scfg
, PVFS_AIO
, false))
60 pvfs
->flags
|= PVFS_FLAG_LINUX_AIO
;
62 /* file perm options */
63 pvfs
->options
.create_mask
= share_int_option(scfg
,
65 SHARE_CREATE_MASK_DEFAULT
);
66 pvfs
->options
.dir_mask
= share_int_option(scfg
,
68 SHARE_DIR_MASK_DEFAULT
);
69 pvfs
->options
.force_dir_mode
= share_int_option(scfg
,
71 SHARE_FORCE_DIR_MODE_DEFAULT
);
72 pvfs
->options
.force_create_mode
= share_int_option(scfg
,
73 SHARE_FORCE_CREATE_MODE
,
74 SHARE_FORCE_CREATE_MODE_DEFAULT
);
75 /* this must be a power of 2 */
76 pvfs
->alloc_size_rounding
= share_int_option(scfg
,
77 PVFS_ALLOCATION_ROUNDING
,
78 PVFS_ALLOCATION_ROUNDING_DEFAULT
);
80 pvfs
->search
.inactivity_time
= share_int_option(scfg
,
81 PVFS_SEARCH_INACTIVITY
,
82 PVFS_SEARCH_INACTIVITY_DEFAULT
);
84 #if HAVE_XATTR_SUPPORT
85 if (share_bool_option(scfg
, PVFS_XATTR
, PVFS_XATTR_DEFAULT
))
86 pvfs
->flags
|= PVFS_FLAG_XATTR_ENABLE
;
89 pvfs
->sharing_violation_delay
= share_int_option(scfg
,
91 PVFS_SHARE_DELAY_DEFAULT
);
93 pvfs
->oplock_break_timeout
= share_int_option(scfg
,
95 PVFS_OPLOCK_TIMEOUT_DEFAULT
);
97 pvfs
->writetime_delay
= share_int_option(scfg
,
99 PVFS_WRITETIME_DELAY_DEFAULT
);
101 pvfs
->share_name
= talloc_strdup(pvfs
, scfg
->name
);
104 FS_ATTR_CASE_SENSITIVE_SEARCH
|
105 FS_ATTR_CASE_PRESERVED_NAMES
|
106 FS_ATTR_UNICODE_ON_DISK
|
107 FS_ATTR_SPARSE_FILES
;
109 /* allow xattrs to be stored in a external tdb */
110 eadb
= share_string_option(scfg
, PVFS_EADB
, NULL
);
112 pvfs
->ea_db
= tdb_wrap_open(pvfs
, eadb
, 50000,
113 TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600);
114 if (pvfs
->ea_db
!= NULL
) {
115 pvfs
->flags
|= PVFS_FLAG_XATTR_ENABLE
;
117 DEBUG(0,("Failed to open eadb '%s' - %s\n",
118 eadb
, strerror(errno
)));
119 pvfs
->flags
&= ~PVFS_FLAG_XATTR_ENABLE
;
123 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
124 pvfs
->fs_attribs
|= FS_ATTR_NAMED_STREAMS
;
126 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
127 pvfs
->fs_attribs
|= FS_ATTR_PERSISTANT_ACLS
;
130 pvfs
->sid_cache
.creator_owner
= dom_sid_parse_talloc(pvfs
, SID_CREATOR_OWNER
);
131 pvfs
->sid_cache
.creator_group
= dom_sid_parse_talloc(pvfs
, SID_CREATOR_GROUP
);
133 /* check if the system really supports xattrs */
134 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
135 pvfs_xattr_probe(pvfs
);
138 /* enable an ACL backend */
139 pvfs
->acl_ops
= pvfs_acl_backend_byname(share_string_option(scfg
, PVFS_ACL
, "xattr"));
142 static int pvfs_state_destructor(struct pvfs_state
*pvfs
)
144 struct pvfs_file
*f
, *fn
;
145 struct pvfs_search_state
*s
, *sn
;
148 * make sure we cleanup files and searches before anything else
149 * because there destructors need to acess the pvfs_state struct
151 for (f
=pvfs
->files
.list
; f
; f
=fn
) {
156 for (s
=pvfs
->search
.list
; s
; s
=sn
) {
165 connect to a share - used when a tree_connect operation comes
166 in. For a disk based backend we needs to ensure that the base
167 directory exists (tho it doesn't need to be accessible by the user,
170 static NTSTATUS
pvfs_connect(struct ntvfs_module_context
*ntvfs
,
171 struct ntvfs_request
*req
, const char *sharename
)
173 struct pvfs_state
*pvfs
;
175 char *base_directory
;
179 * TODO: call this from ntvfs_posix_init()
180 * but currently we don't have a lp_ctx there
182 status
= pvfs_acl_init(ntvfs
->ctx
->lp_ctx
);
183 NT_STATUS_NOT_OK_RETURN(status
);
185 pvfs
= talloc_zero(ntvfs
, struct pvfs_state
);
186 NT_STATUS_HAVE_NO_MEMORY(pvfs
);
188 /* for simplicity of path construction, remove any trailing slash now */
189 base_directory
= talloc_strdup(pvfs
, share_string_option(ntvfs
->ctx
->config
, SHARE_PATH
, ""));
190 NT_STATUS_HAVE_NO_MEMORY(base_directory
);
191 if (strcmp(base_directory
, "/") != 0) {
192 trim_string(base_directory
, NULL
, "/");
196 pvfs
->base_directory
= base_directory
;
198 /* the directory must exist. Note that we deliberately don't
199 check that it is readable */
200 if (stat(pvfs
->base_directory
, &st
) != 0 || !S_ISDIR(st
.st_mode
)) {
201 DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n",
202 pvfs
->base_directory
, sharename
));
203 return NT_STATUS_BAD_NETWORK_NAME
;
206 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
207 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
209 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
210 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
212 ntvfs
->private_data
= pvfs
;
214 pvfs
->brl_context
= brl_init(pvfs
,
215 pvfs
->ntvfs
->ctx
->server_id
,
216 pvfs
->ntvfs
->ctx
->lp_ctx
,
217 pvfs
->ntvfs
->ctx
->msg_ctx
);
218 if (pvfs
->brl_context
== NULL
) {
219 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
222 pvfs
->odb_context
= odb_init(pvfs
, pvfs
->ntvfs
->ctx
);
223 if (pvfs
->odb_context
== NULL
) {
224 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
227 /* allow this to be NULL - we just disable change notify */
228 pvfs
->notify_context
= notify_init(pvfs
,
229 pvfs
->ntvfs
->ctx
->server_id
,
230 pvfs
->ntvfs
->ctx
->msg_ctx
,
231 pvfs
->ntvfs
->ctx
->lp_ctx
,
232 pvfs
->ntvfs
->ctx
->event_ctx
,
233 pvfs
->ntvfs
->ctx
->config
);
235 pvfs
->wbc_ctx
= wbc_init(pvfs
,
236 pvfs
->ntvfs
->ctx
->msg_ctx
,
237 pvfs
->ntvfs
->ctx
->event_ctx
);
238 if (pvfs
->wbc_ctx
== NULL
) {
239 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
242 /* allocate the search handle -> ptr tree */
243 pvfs
->search
.idtree
= idr_init(pvfs
);
244 NT_STATUS_HAVE_NO_MEMORY(pvfs
->search
.idtree
);
246 status
= pvfs_mangle_init(pvfs
);
247 NT_STATUS_NOT_OK_RETURN(status
);
249 pvfs_setup_options(pvfs
);
251 talloc_set_destructor(pvfs
, pvfs_state_destructor
);
254 /* who had the stupid idea to generate a signal on a large
255 file write instead of just failing it!? */
256 BlockSignals(true, SIGXFSZ
);
263 disconnect from a share
265 static NTSTATUS
pvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
271 check if a directory exists
273 static NTSTATUS
pvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
274 struct ntvfs_request
*req
,
275 union smb_chkpath
*cp
)
277 struct pvfs_state
*pvfs
= ntvfs
->private_data
;
278 struct pvfs_filename
*name
;
281 /* resolve the cifs name to a posix name */
282 status
= pvfs_resolve_name(pvfs
, req
, cp
->chkpath
.in
.path
, 0, &name
);
283 NT_STATUS_NOT_OK_RETURN(status
);
286 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
289 if (!S_ISDIR(name
->st
.st_mode
)) {
290 return NT_STATUS_NOT_A_DIRECTORY
;
299 static NTSTATUS
pvfs_copy(struct ntvfs_module_context
*ntvfs
,
300 struct ntvfs_request
*req
, struct smb_copy
*cp
)
302 DEBUG(0,("pvfs_copy not implemented\n"));
303 return NT_STATUS_NOT_SUPPORTED
;
307 return print queue info
309 static NTSTATUS
pvfs_lpq(struct ntvfs_module_context
*ntvfs
,
310 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
312 return NT_STATUS_NOT_SUPPORTED
;
315 /* SMBtrans - not used on file shares */
316 static NTSTATUS
pvfs_trans(struct ntvfs_module_context
*ntvfs
,
317 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
319 return NT_STATUS_ACCESS_DENIED
;
323 initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
325 NTSTATUS
ntvfs_posix_init(void)
328 struct ntvfs_ops ops
;
329 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
333 ops
.type
= NTVFS_DISK
;
335 /* fill in all the operations */
336 ops
.connect
= pvfs_connect
;
337 ops
.disconnect
= pvfs_disconnect
;
338 ops
.unlink
= pvfs_unlink
;
339 ops
.chkpath
= pvfs_chkpath
;
340 ops
.qpathinfo
= pvfs_qpathinfo
;
341 ops
.setpathinfo
= pvfs_setpathinfo
;
342 ops
.open
= pvfs_open
;
343 ops
.mkdir
= pvfs_mkdir
;
344 ops
.rmdir
= pvfs_rmdir
;
345 ops
.rename
= pvfs_rename
;
346 ops
.copy
= pvfs_copy
;
347 ops
.ioctl
= pvfs_ioctl
;
348 ops
.read
= pvfs_read
;
349 ops
.write
= pvfs_write
;
350 ops
.seek
= pvfs_seek
;
351 ops
.flush
= pvfs_flush
;
352 ops
.close
= pvfs_close
;
353 ops
.exit
= pvfs_exit
;
354 ops
.lock
= pvfs_lock
;
355 ops
.setfileinfo
= pvfs_setfileinfo
;
356 ops
.qfileinfo
= pvfs_qfileinfo
;
357 ops
.fsinfo
= pvfs_fsinfo
;
359 ops
.search_first
= pvfs_search_first
;
360 ops
.search_next
= pvfs_search_next
;
361 ops
.search_close
= pvfs_search_close
;
362 ops
.trans
= pvfs_trans
;
363 ops
.logoff
= pvfs_logoff
;
364 ops
.async_setup
= pvfs_async_setup
;
365 ops
.cancel
= pvfs_cancel
;
366 ops
.notify
= pvfs_notify
;
368 /* register ourselves with the NTVFS subsystem. We register
369 under the name 'default' as we wish to be the default
370 backend, and also register as 'posix' */
371 ops
.name
= "default";
372 ret
= ntvfs_register(&ops
, &vers
);
374 if (!NT_STATUS_IS_OK(ret
)) {
375 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops
.name
));
379 ret
= ntvfs_register(&ops
, &vers
);
381 if (!NT_STATUS_IS_OK(ret
)) {
382 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops
.name
));
385 if (NT_STATUS_IS_OK(ret
)) {
386 ret
= ntvfs_common_init();