1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 | Wrap disk only vfs functions to sidestep dodgy compilers.
|
---|
4 | Copyright (C) Tim Potter 1998
|
---|
5 | Copyright (C) Jeremy Allison 2007
|
---|
6 |
|
---|
7 | This program is free software; you can redistribute it and/or modify
|
---|
8 | it under the terms of the GNU General Public License as published by
|
---|
9 | the Free Software Foundation; either version 3 of the License, or
|
---|
10 | (at your option) any later version.
|
---|
11 |
|
---|
12 | This program is distributed in the hope that it will be useful,
|
---|
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
15 | GNU General Public License for more details.
|
---|
16 |
|
---|
17 | You should have received a copy of the GNU General Public License
|
---|
18 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | */
|
---|
20 |
|
---|
21 | #include "includes.h"
|
---|
22 | #include "system/time.h"
|
---|
23 | #include "system/filesys.h"
|
---|
24 | #include "smbd/smbd.h"
|
---|
25 | #include "smbd/globals.h"
|
---|
26 | #include "ntioctl.h"
|
---|
27 | #include "smbprofile.h"
|
---|
28 | #include "../libcli/security/security.h"
|
---|
29 | #include "passdb/lookup_sid.h"
|
---|
30 | #include "source3/include/msdfs.h"
|
---|
31 | #include "librpc/gen_ndr/ndr_dfsblobs.h"
|
---|
32 | #include "lib/util/tevent_unix.h"
|
---|
33 | #include "lib/asys/asys.h"
|
---|
34 | #include "lib/util/tevent_ntstatus.h"
|
---|
35 | #include "lib/util/sys_rw.h"
|
---|
36 |
|
---|
37 | #undef DBGC_CLASS
|
---|
38 | #define DBGC_CLASS DBGC_VFS
|
---|
39 |
|
---|
40 | /* Check for NULL pointer parameters in vfswrap_* functions */
|
---|
41 |
|
---|
42 | /* We don't want to have NULL function pointers lying around. Someone
|
---|
43 | is sure to try and execute them. These stubs are used to prevent
|
---|
44 | this possibility. */
|
---|
45 |
|
---|
46 | static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
|
---|
47 | {
|
---|
48 | return 0; /* Return >= 0 for success */
|
---|
49 | }
|
---|
50 |
|
---|
51 | static void vfswrap_disconnect(vfs_handle_struct *handle)
|
---|
52 | {
|
---|
53 | }
|
---|
54 |
|
---|
55 | /* Disk operations */
|
---|
56 |
|
---|
57 | static uint64_t vfswrap_disk_free(vfs_handle_struct *handle, const char *path,
|
---|
58 | uint64_t *bsize, uint64_t *dfree,
|
---|
59 | uint64_t *dsize)
|
---|
60 | {
|
---|
61 | if (sys_fsusage(path, dfree, dsize) != 0) {
|
---|
62 | return (uint64_t)-1;
|
---|
63 | }
|
---|
64 |
|
---|
65 | *bsize = 512;
|
---|
66 | return *dfree / 2;
|
---|
67 | }
|
---|
68 |
|
---|
69 | static int vfswrap_get_quota(struct vfs_handle_struct *handle, const char *path,
|
---|
70 | enum SMB_QUOTA_TYPE qtype, unid_t id,
|
---|
71 | SMB_DISK_QUOTA *qt)
|
---|
72 | {
|
---|
73 | #ifdef HAVE_SYS_QUOTAS
|
---|
74 | int result;
|
---|
75 |
|
---|
76 | START_PROFILE(syscall_get_quota);
|
---|
77 | result = sys_get_quota(path, qtype, id, qt);
|
---|
78 | END_PROFILE(syscall_get_quota);
|
---|
79 | return result;
|
---|
80 | #else
|
---|
81 | errno = ENOSYS;
|
---|
82 | return -1;
|
---|
83 | #endif
|
---|
84 | }
|
---|
85 |
|
---|
86 | static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
|
---|
87 | {
|
---|
88 | #ifdef HAVE_SYS_QUOTAS
|
---|
89 | int result;
|
---|
90 |
|
---|
91 | START_PROFILE(syscall_set_quota);
|
---|
92 | result = sys_set_quota(handle->conn->connectpath, qtype, id, qt);
|
---|
93 | END_PROFILE(syscall_set_quota);
|
---|
94 | return result;
|
---|
95 | #else
|
---|
96 | errno = ENOSYS;
|
---|
97 | return -1;
|
---|
98 | #endif
|
---|
99 | }
|
---|
100 |
|
---|
101 | static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
|
---|
102 | struct files_struct *fsp,
|
---|
103 | struct shadow_copy_data *shadow_copy_data,
|
---|
104 | bool labels)
|
---|
105 | {
|
---|
106 | errno = ENOSYS;
|
---|
107 | return -1; /* Not implemented. */
|
---|
108 | }
|
---|
109 |
|
---|
110 | static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
|
---|
111 | {
|
---|
112 | return sys_statvfs(path, statbuf);
|
---|
113 | }
|
---|
114 |
|
---|
115 | static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
|
---|
116 | enum timestamp_set_resolution *p_ts_res)
|
---|
117 | {
|
---|
118 | connection_struct *conn = handle->conn;
|
---|
119 | uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
|
---|
120 | struct smb_filename *smb_fname_cpath = NULL;
|
---|
121 | struct vfs_statvfs_struct statbuf;
|
---|
122 | int ret;
|
---|
123 |
|
---|
124 | ZERO_STRUCT(statbuf);
|
---|
125 | ret = sys_statvfs(conn->connectpath, &statbuf);
|
---|
126 | if (ret == 0) {
|
---|
127 | caps = statbuf.FsCapabilities;
|
---|
128 | }
|
---|
129 |
|
---|
130 | *p_ts_res = TIMESTAMP_SET_SECONDS;
|
---|
131 |
|
---|
132 | /* Work out what timestamp resolution we can
|
---|
133 | * use when setting a timestamp. */
|
---|
134 |
|
---|
135 | smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath,
|
---|
136 | NULL, NULL);
|
---|
137 | if (smb_fname_cpath == NULL) {
|
---|
138 | return caps;
|
---|
139 | }
|
---|
140 |
|
---|
141 | ret = SMB_VFS_STAT(conn, smb_fname_cpath);
|
---|
142 | if (ret == -1) {
|
---|
143 | TALLOC_FREE(smb_fname_cpath);
|
---|
144 | return caps;
|
---|
145 | }
|
---|
146 |
|
---|
147 | if (smb_fname_cpath->st.st_ex_mtime.tv_nsec ||
|
---|
148 | smb_fname_cpath->st.st_ex_atime.tv_nsec ||
|
---|
149 | smb_fname_cpath->st.st_ex_ctime.tv_nsec) {
|
---|
150 | /* If any of the normal UNIX directory timestamps
|
---|
151 | * have a non-zero tv_nsec component assume
|
---|
152 | * we might be able to set sub-second timestamps.
|
---|
153 | * See what filetime set primitives we have.
|
---|
154 | */
|
---|
155 | #if defined(HAVE_UTIMENSAT)
|
---|
156 | *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
|
---|
157 | #elif defined(HAVE_UTIMES)
|
---|
158 | /* utimes allows msec timestamps to be set. */
|
---|
159 | *p_ts_res = TIMESTAMP_SET_MSEC;
|
---|
160 | #elif defined(HAVE_UTIME)
|
---|
161 | /* utime only allows sec timestamps to be set. */
|
---|
162 | *p_ts_res = TIMESTAMP_SET_SECONDS;
|
---|
163 | #endif
|
---|
164 |
|
---|
165 | DEBUG(10,("vfswrap_fs_capabilities: timestamp "
|
---|
166 | "resolution of %s "
|
---|
167 | "available on share %s, directory %s\n",
|
---|
168 | *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
|
---|
169 | lp_servicename(talloc_tos(), conn->params->service),
|
---|
170 | conn->connectpath ));
|
---|
171 | }
|
---|
172 | TALLOC_FREE(smb_fname_cpath);
|
---|
173 | return caps;
|
---|
174 | }
|
---|
175 |
|
---|
176 | static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
|
---|
177 | struct dfs_GetDFSReferral *r)
|
---|
178 | {
|
---|
179 | struct junction_map *junction = NULL;
|
---|
180 | int consumedcnt = 0;
|
---|
181 | bool self_referral = false;
|
---|
182 | char *pathnamep = NULL;
|
---|
183 | char *local_dfs_path = NULL;
|
---|
184 | NTSTATUS status;
|
---|
185 | int i;
|
---|
186 | uint16_t max_referral_level = r->in.req.max_referral_level;
|
---|
187 |
|
---|
188 | if (DEBUGLVL(10)) {
|
---|
189 | NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
|
---|
190 | }
|
---|
191 |
|
---|
192 | /* get the junction entry */
|
---|
193 | if (r->in.req.servername == NULL) {
|
---|
194 | return NT_STATUS_NOT_FOUND;
|
---|
195 | }
|
---|
196 |
|
---|
197 | /*
|
---|
198 | * Trim pathname sent by client so it begins with only one backslash.
|
---|
199 | * Two backslashes confuse some dfs clients
|
---|
200 | */
|
---|
201 |
|
---|
202 | local_dfs_path = talloc_strdup(r, r->in.req.servername);
|
---|
203 | if (local_dfs_path == NULL) {
|
---|
204 | return NT_STATUS_NO_MEMORY;
|
---|
205 | }
|
---|
206 | pathnamep = local_dfs_path;
|
---|
207 | while (IS_DIRECTORY_SEP(pathnamep[0]) &&
|
---|
208 | IS_DIRECTORY_SEP(pathnamep[1])) {
|
---|
209 | pathnamep++;
|
---|
210 | }
|
---|
211 |
|
---|
212 | junction = talloc_zero(r, struct junction_map);
|
---|
213 | if (junction == NULL) {
|
---|
214 | return NT_STATUS_NO_MEMORY;
|
---|
215 | }
|
---|
216 |
|
---|
217 | /* The following call can change cwd. */
|
---|
218 | status = get_referred_path(r, pathnamep,
|
---|
219 | !handle->conn->sconn->using_smb2,
|
---|
220 | junction, &consumedcnt, &self_referral);
|
---|
221 | if (!NT_STATUS_IS_OK(status)) {
|
---|
222 | vfs_ChDir(handle->conn, handle->conn->connectpath);
|
---|
223 | return status;
|
---|
224 | }
|
---|
225 | vfs_ChDir(handle->conn, handle->conn->connectpath);
|
---|
226 |
|
---|
227 | if (!self_referral) {
|
---|
228 | pathnamep[consumedcnt] = '\0';
|
---|
229 |
|
---|
230 | if (DEBUGLVL(3)) {
|
---|
231 | dbgtext("Path %s to alternate path(s):",
|
---|
232 | pathnamep);
|
---|
233 | for (i=0; i < junction->referral_count; i++) {
|
---|
234 | dbgtext(" %s",
|
---|
235 | junction->referral_list[i].alternate_path);
|
---|
236 | }
|
---|
237 | dbgtext(".\n");
|
---|
238 | }
|
---|
239 | }
|
---|
240 |
|
---|
241 | if (r->in.req.max_referral_level <= 2) {
|
---|
242 | max_referral_level = 2;
|
---|
243 | }
|
---|
244 | if (r->in.req.max_referral_level >= 3) {
|
---|
245 | max_referral_level = 3;
|
---|
246 | }
|
---|
247 |
|
---|
248 | r->out.resp = talloc_zero(r, struct dfs_referral_resp);
|
---|
249 | if (r->out.resp == NULL) {
|
---|
250 | return NT_STATUS_NO_MEMORY;
|
---|
251 | }
|
---|
252 |
|
---|
253 | r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
|
---|
254 | r->out.resp->nb_referrals = junction->referral_count;
|
---|
255 |
|
---|
256 | r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
|
---|
257 | if (self_referral) {
|
---|
258 | r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
|
---|
259 | }
|
---|
260 |
|
---|
261 | r->out.resp->referral_entries = talloc_zero_array(r,
|
---|
262 | struct dfs_referral_type,
|
---|
263 | r->out.resp->nb_referrals);
|
---|
264 | if (r->out.resp->referral_entries == NULL) {
|
---|
265 | return NT_STATUS_NO_MEMORY;
|
---|
266 | }
|
---|
267 |
|
---|
268 | switch (max_referral_level) {
|
---|
269 | case 2:
|
---|
270 | for(i=0; i < junction->referral_count; i++) {
|
---|
271 | struct referral *ref = &junction->referral_list[i];
|
---|
272 | TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
|
---|
273 | struct dfs_referral_type *t =
|
---|
274 | &r->out.resp->referral_entries[i];
|
---|
275 | struct dfs_referral_v2 *v2 = &t->referral.v2;
|
---|
276 |
|
---|
277 | t->version = 2;
|
---|
278 | v2->size = VERSION2_REFERRAL_SIZE;
|
---|
279 | if (self_referral) {
|
---|
280 | v2->server_type = DFS_SERVER_ROOT;
|
---|
281 | } else {
|
---|
282 | v2->server_type = DFS_SERVER_NON_ROOT;
|
---|
283 | }
|
---|
284 | v2->entry_flags = 0;
|
---|
285 | v2->proximity = ref->proximity;
|
---|
286 | v2->ttl = ref->ttl;
|
---|
287 | v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
|
---|
288 | if (v2->DFS_path == NULL) {
|
---|
289 | return NT_STATUS_NO_MEMORY;
|
---|
290 | }
|
---|
291 | v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
|
---|
292 | if (v2->DFS_alt_path == NULL) {
|
---|
293 | return NT_STATUS_NO_MEMORY;
|
---|
294 | }
|
---|
295 | v2->netw_address = talloc_strdup(mem_ctx,
|
---|
296 | ref->alternate_path);
|
---|
297 | if (v2->netw_address == NULL) {
|
---|
298 | return NT_STATUS_NO_MEMORY;
|
---|
299 | }
|
---|
300 | }
|
---|
301 |
|
---|
302 | break;
|
---|
303 | case 3:
|
---|
304 | for(i=0; i < junction->referral_count; i++) {
|
---|
305 | struct referral *ref = &junction->referral_list[i];
|
---|
306 | TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
|
---|
307 | struct dfs_referral_type *t =
|
---|
308 | &r->out.resp->referral_entries[i];
|
---|
309 | struct dfs_referral_v3 *v3 = &t->referral.v3;
|
---|
310 | struct dfs_normal_referral *r1 = &v3->referrals.r1;
|
---|
311 |
|
---|
312 | t->version = 3;
|
---|
313 | v3->size = VERSION3_REFERRAL_SIZE;
|
---|
314 | if (self_referral) {
|
---|
315 | v3->server_type = DFS_SERVER_ROOT;
|
---|
316 | } else {
|
---|
317 | v3->server_type = DFS_SERVER_NON_ROOT;
|
---|
318 | }
|
---|
319 | v3->entry_flags = 0;
|
---|
320 | v3->ttl = ref->ttl;
|
---|
321 | r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
|
---|
322 | if (r1->DFS_path == NULL) {
|
---|
323 | return NT_STATUS_NO_MEMORY;
|
---|
324 | }
|
---|
325 | r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
|
---|
326 | if (r1->DFS_alt_path == NULL) {
|
---|
327 | return NT_STATUS_NO_MEMORY;
|
---|
328 | }
|
---|
329 | r1->netw_address = talloc_strdup(mem_ctx,
|
---|
330 | ref->alternate_path);
|
---|
331 | if (r1->netw_address == NULL) {
|
---|
332 | return NT_STATUS_NO_MEMORY;
|
---|
333 | }
|
---|
334 | }
|
---|
335 | break;
|
---|
336 | default:
|
---|
337 | DEBUG(0,("Invalid dfs referral version: %d\n",
|
---|
338 | max_referral_level));
|
---|
339 | return NT_STATUS_INVALID_LEVEL;
|
---|
340 | }
|
---|
341 |
|
---|
342 | if (DEBUGLVL(10)) {
|
---|
343 | NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
|
---|
344 | }
|
---|
345 |
|
---|
346 | return NT_STATUS_OK;
|
---|
347 | }
|
---|
348 |
|
---|
349 | static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
|
---|
350 | TALLOC_CTX *mem_ctx,
|
---|
351 | const char *service_path,
|
---|
352 | char **base_volume)
|
---|
353 | {
|
---|
354 | return NT_STATUS_NOT_SUPPORTED;
|
---|
355 | }
|
---|
356 |
|
---|
357 | static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
|
---|
358 | TALLOC_CTX *mem_ctx,
|
---|
359 | const char *base_volume,
|
---|
360 | time_t *tstamp,
|
---|
361 | bool rw,
|
---|
362 | char **base_path,
|
---|
363 | char **snap_path)
|
---|
364 | {
|
---|
365 | return NT_STATUS_NOT_SUPPORTED;
|
---|
366 | }
|
---|
367 |
|
---|
368 | static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
|
---|
369 | TALLOC_CTX *mem_ctx,
|
---|
370 | char *base_path,
|
---|
371 | char *snap_path)
|
---|
372 | {
|
---|
373 | return NT_STATUS_NOT_SUPPORTED;
|
---|
374 | }
|
---|
375 |
|
---|
376 | /* Directory operations */
|
---|
377 |
|
---|
378 | static DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32_t attr)
|
---|
379 | {
|
---|
380 | DIR *result;
|
---|
381 |
|
---|
382 | START_PROFILE(syscall_opendir);
|
---|
383 | result = opendir(fname);
|
---|
384 | END_PROFILE(syscall_opendir);
|
---|
385 | return result;
|
---|
386 | }
|
---|
387 |
|
---|
388 | static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
|
---|
389 | files_struct *fsp,
|
---|
390 | const char *mask,
|
---|
391 | uint32_t attr)
|
---|
392 | {
|
---|
393 | DIR *result;
|
---|
394 |
|
---|
395 | START_PROFILE(syscall_fdopendir);
|
---|
396 | result = sys_fdopendir(fsp->fh->fd);
|
---|
397 | END_PROFILE(syscall_fdopendir);
|
---|
398 | return result;
|
---|
399 | }
|
---|
400 |
|
---|
401 |
|
---|
402 | static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
|
---|
403 | DIR *dirp,
|
---|
404 | SMB_STRUCT_STAT *sbuf)
|
---|
405 | {
|
---|
406 | struct dirent *result;
|
---|
407 |
|
---|
408 | START_PROFILE(syscall_readdir);
|
---|
409 | result = readdir(dirp);
|
---|
410 | END_PROFILE(syscall_readdir);
|
---|
411 | if (sbuf) {
|
---|
412 | /* Default Posix readdir() does not give us stat info.
|
---|
413 | * Set to invalid to indicate we didn't return this info. */
|
---|
414 | SET_STAT_INVALID(*sbuf);
|
---|
415 | #if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)
|
---|
416 | if (result != NULL) {
|
---|
417 | /* See if we can efficiently return this. */
|
---|
418 | struct stat st;
|
---|
419 | int flags = (lp_posix_pathnames() ?
|
---|
420 | AT_SYMLINK_NOFOLLOW : 0);
|
---|
421 | int ret = fstatat(dirfd(dirp),
|
---|
422 | result->d_name,
|
---|
423 | &st,
|
---|
424 | flags);
|
---|
425 | if (ret == 0) {
|
---|
426 | init_stat_ex_from_stat(sbuf,
|
---|
427 | &st,
|
---|
428 | lp_fake_directory_create_times(
|
---|
429 | SNUM(handle->conn)));
|
---|
430 | }
|
---|
431 | }
|
---|
432 | #endif
|
---|
433 | }
|
---|
434 | return result;
|
---|
435 | }
|
---|
436 |
|
---|
437 | static NTSTATUS vfswrap_readdir_attr(struct vfs_handle_struct *handle,
|
---|
438 | const struct smb_filename *fname,
|
---|
439 | TALLOC_CTX *mem_ctx,
|
---|
440 | struct readdir_attr_data **attr_data)
|
---|
441 | {
|
---|
442 | return NT_STATUS_NOT_SUPPORTED;
|
---|
443 | }
|
---|
444 |
|
---|
445 | static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
|
---|
446 | {
|
---|
447 | START_PROFILE(syscall_seekdir);
|
---|
448 | seekdir(dirp, offset);
|
---|
449 | END_PROFILE(syscall_seekdir);
|
---|
450 | }
|
---|
451 |
|
---|
452 | static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
|
---|
453 | {
|
---|
454 | long result;
|
---|
455 | START_PROFILE(syscall_telldir);
|
---|
456 | result = telldir(dirp);
|
---|
457 | END_PROFILE(syscall_telldir);
|
---|
458 | return result;
|
---|
459 | }
|
---|
460 |
|
---|
461 | static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
|
---|
462 | {
|
---|
463 | START_PROFILE(syscall_rewinddir);
|
---|
464 | rewinddir(dirp);
|
---|
465 | END_PROFILE(syscall_rewinddir);
|
---|
466 | }
|
---|
467 |
|
---|
468 | static int vfswrap_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode)
|
---|
469 | {
|
---|
470 | int result;
|
---|
471 | bool has_dacl = False;
|
---|
472 | char *parent = NULL;
|
---|
473 |
|
---|
474 | START_PROFILE(syscall_mkdir);
|
---|
475 |
|
---|
476 | if (lp_inherit_acls(SNUM(handle->conn))
|
---|
477 | && parent_dirname(talloc_tos(), path, &parent, NULL)
|
---|
478 | && (has_dacl = directory_has_default_acl(handle->conn, parent))) {
|
---|
479 | mode = (0777 & lp_directory_mask(SNUM(handle->conn)));
|
---|
480 | }
|
---|
481 |
|
---|
482 | TALLOC_FREE(parent);
|
---|
483 |
|
---|
484 | result = mkdir(path, mode);
|
---|
485 |
|
---|
486 | if (result == 0 && !has_dacl) {
|
---|
487 | /*
|
---|
488 | * We need to do this as the default behavior of POSIX ACLs
|
---|
489 | * is to set the mask to be the requested group permission
|
---|
490 | * bits, not the group permission bits to be the requested
|
---|
491 | * group permission bits. This is not what we want, as it will
|
---|
492 | * mess up any inherited ACL bits that were set. JRA.
|
---|
493 | */
|
---|
494 | int saved_errno = errno; /* We may get ENOSYS */
|
---|
495 | if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
|
---|
496 | errno = saved_errno;
|
---|
497 | }
|
---|
498 |
|
---|
499 | END_PROFILE(syscall_mkdir);
|
---|
500 | return result;
|
---|
501 | }
|
---|
502 |
|
---|
503 | static int vfswrap_rmdir(vfs_handle_struct *handle, const char *path)
|
---|
504 | {
|
---|
505 | int result;
|
---|
506 |
|
---|
507 | START_PROFILE(syscall_rmdir);
|
---|
508 | result = rmdir(path);
|
---|
509 | END_PROFILE(syscall_rmdir);
|
---|
510 | return result;
|
---|
511 | }
|
---|
512 |
|
---|
513 | static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
|
---|
514 | {
|
---|
515 | int result;
|
---|
516 |
|
---|
517 | START_PROFILE(syscall_closedir);
|
---|
518 | result = closedir(dirp);
|
---|
519 | END_PROFILE(syscall_closedir);
|
---|
520 | return result;
|
---|
521 | }
|
---|
522 |
|
---|
523 | static void vfswrap_init_search_op(vfs_handle_struct *handle,
|
---|
524 | DIR *dirp)
|
---|
525 | {
|
---|
526 | /* Default behavior is a NOOP */
|
---|
527 | }
|
---|
528 |
|
---|
529 | /* File operations */
|
---|
530 |
|
---|
531 | static int vfswrap_open(vfs_handle_struct *handle,
|
---|
532 | struct smb_filename *smb_fname,
|
---|
533 | files_struct *fsp, int flags, mode_t mode)
|
---|
534 | {
|
---|
535 | int result = -1;
|
---|
536 |
|
---|
537 | START_PROFILE(syscall_open);
|
---|
538 |
|
---|
539 | if (smb_fname->stream_name) {
|
---|
540 | errno = ENOENT;
|
---|
541 | goto out;
|
---|
542 | }
|
---|
543 |
|
---|
544 | result = open(smb_fname->base_name, flags, mode);
|
---|
545 | out:
|
---|
546 | END_PROFILE(syscall_open);
|
---|
547 | return result;
|
---|
548 | }
|
---|
549 |
|
---|
550 | static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
|
---|
551 | struct smb_request *req,
|
---|
552 | uint16_t root_dir_fid,
|
---|
553 | struct smb_filename *smb_fname,
|
---|
554 | uint32_t access_mask,
|
---|
555 | uint32_t share_access,
|
---|
556 | uint32_t create_disposition,
|
---|
557 | uint32_t create_options,
|
---|
558 | uint32_t file_attributes,
|
---|
559 | uint32_t oplock_request,
|
---|
560 | struct smb2_lease *lease,
|
---|
561 | uint64_t allocation_size,
|
---|
562 | uint32_t private_flags,
|
---|
563 | struct security_descriptor *sd,
|
---|
564 | struct ea_list *ea_list,
|
---|
565 | files_struct **result,
|
---|
566 | int *pinfo,
|
---|
567 | const struct smb2_create_blobs *in_context_blobs,
|
---|
568 | struct smb2_create_blobs *out_context_blobs)
|
---|
569 | {
|
---|
570 | return create_file_default(handle->conn, req, root_dir_fid, smb_fname,
|
---|
571 | access_mask, share_access,
|
---|
572 | create_disposition, create_options,
|
---|
573 | file_attributes, oplock_request, lease,
|
---|
574 | allocation_size, private_flags,
|
---|
575 | sd, ea_list, result,
|
---|
576 | pinfo, in_context_blobs, out_context_blobs);
|
---|
577 | }
|
---|
578 |
|
---|
579 | static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
|
---|
580 | {
|
---|
581 | int result;
|
---|
582 |
|
---|
583 | START_PROFILE(syscall_close);
|
---|
584 | result = fd_close_posix(fsp);
|
---|
585 | END_PROFILE(syscall_close);
|
---|
586 | return result;
|
---|
587 | }
|
---|
588 |
|
---|
589 | static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
|
---|
590 | {
|
---|
591 | ssize_t result;
|
---|
592 |
|
---|
593 | START_PROFILE_BYTES(syscall_read, n);
|
---|
594 | result = sys_read(fsp->fh->fd, data, n);
|
---|
595 | END_PROFILE_BYTES(syscall_read);
|
---|
596 | return result;
|
---|
597 | }
|
---|
598 |
|
---|
599 | static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
|
---|
600 | size_t n, off_t offset)
|
---|
601 | {
|
---|
602 | ssize_t result;
|
---|
603 |
|
---|
604 | #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
|
---|
605 | START_PROFILE_BYTES(syscall_pread, n);
|
---|
606 | result = sys_pread(fsp->fh->fd, data, n, offset);
|
---|
607 | END_PROFILE_BYTES(syscall_pread);
|
---|
608 |
|
---|
609 | if (result == -1 && errno == ESPIPE) {
|
---|
610 | /* Maintain the fiction that pipes can be seeked (sought?) on. */
|
---|
611 | result = SMB_VFS_READ(fsp, data, n);
|
---|
612 | fsp->fh->pos = 0;
|
---|
613 | }
|
---|
614 |
|
---|
615 | #else /* HAVE_PREAD */
|
---|
616 | off_t curr;
|
---|
617 | int lerrno;
|
---|
618 |
|
---|
619 | curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
|
---|
620 | if (curr == -1 && errno == ESPIPE) {
|
---|
621 | /* Maintain the fiction that pipes can be seeked (sought?) on. */
|
---|
622 | result = SMB_VFS_READ(fsp, data, n);
|
---|
623 | fsp->fh->pos = 0;
|
---|
624 | return result;
|
---|
625 | }
|
---|
626 |
|
---|
627 | if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
|
---|
628 | return -1;
|
---|
629 | }
|
---|
630 |
|
---|
631 | errno = 0;
|
---|
632 | result = SMB_VFS_READ(fsp, data, n);
|
---|
633 | lerrno = errno;
|
---|
634 |
|
---|
635 | SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
|
---|
636 | errno = lerrno;
|
---|
637 |
|
---|
638 | #endif /* HAVE_PREAD */
|
---|
639 |
|
---|
640 | return result;
|
---|
641 | }
|
---|
642 |
|
---|
643 | static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
|
---|
644 | {
|
---|
645 | ssize_t result;
|
---|
646 |
|
---|
647 | START_PROFILE_BYTES(syscall_write, n);
|
---|
648 | result = sys_write(fsp->fh->fd, data, n);
|
---|
649 | END_PROFILE_BYTES(syscall_write);
|
---|
650 | return result;
|
---|
651 | }
|
---|
652 |
|
---|
653 | static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
|
---|
654 | size_t n, off_t offset)
|
---|
655 | {
|
---|
656 | ssize_t result;
|
---|
657 |
|
---|
658 | #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
|
---|
659 | START_PROFILE_BYTES(syscall_pwrite, n);
|
---|
660 | result = sys_pwrite(fsp->fh->fd, data, n, offset);
|
---|
661 | END_PROFILE_BYTES(syscall_pwrite);
|
---|
662 |
|
---|
663 | if (result == -1 && errno == ESPIPE) {
|
---|
664 | /* Maintain the fiction that pipes can be sought on. */
|
---|
665 | result = SMB_VFS_WRITE(fsp, data, n);
|
---|
666 | }
|
---|
667 |
|
---|
668 | #else /* HAVE_PWRITE */
|
---|
669 | off_t curr;
|
---|
670 | int lerrno;
|
---|
671 |
|
---|
672 | curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
|
---|
673 | if (curr == -1) {
|
---|
674 | return -1;
|
---|
675 | }
|
---|
676 |
|
---|
677 | if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
|
---|
678 | return -1;
|
---|
679 | }
|
---|
680 |
|
---|
681 | result = SMB_VFS_WRITE(fsp, data, n);
|
---|
682 | lerrno = errno;
|
---|
683 |
|
---|
684 | SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
|
---|
685 | errno = lerrno;
|
---|
686 |
|
---|
687 | #endif /* HAVE_PWRITE */
|
---|
688 |
|
---|
689 | return result;
|
---|
690 | }
|
---|
691 |
|
---|
692 | static void vfswrap_asys_finished(struct tevent_context *ev,
|
---|
693 | struct tevent_fd *fde,
|
---|
694 | uint16_t flags, void *p);
|
---|
695 |
|
---|
696 | static bool vfswrap_init_asys_ctx(struct smbd_server_connection *conn)
|
---|
697 | {
|
---|
698 | struct asys_context *ctx;
|
---|
699 | struct tevent_fd *fde;
|
---|
700 | int ret;
|
---|
701 | int fd;
|
---|
702 |
|
---|
703 | if (conn->asys_ctx != NULL) {
|
---|
704 | return true;
|
---|
705 | }
|
---|
706 |
|
---|
707 | ret = asys_context_init(&ctx, lp_aio_max_threads());
|
---|
708 | if (ret != 0) {
|
---|
709 | DEBUG(1, ("asys_context_init failed: %s\n", strerror(ret)));
|
---|
710 | return false;
|
---|
711 | }
|
---|
712 |
|
---|
713 | fd = asys_signalfd(ctx);
|
---|
714 |
|
---|
715 | ret = set_blocking(fd, false);
|
---|
716 | if (ret != 0) {
|
---|
717 | DBG_WARNING("set_blocking failed: %s\n", strerror(errno));
|
---|
718 | goto fail;
|
---|
719 | }
|
---|
720 |
|
---|
721 | fde = tevent_add_fd(conn->ev_ctx, conn, fd, TEVENT_FD_READ,
|
---|
722 | vfswrap_asys_finished, ctx);
|
---|
723 | if (fde == NULL) {
|
---|
724 | DEBUG(1, ("tevent_add_fd failed\n"));
|
---|
725 | goto fail;
|
---|
726 | }
|
---|
727 |
|
---|
728 | conn->asys_ctx = ctx;
|
---|
729 | conn->asys_fde = fde;
|
---|
730 | return true;
|
---|
731 |
|
---|
732 | fail:
|
---|
733 | asys_context_destroy(ctx);
|
---|
734 | return false;
|
---|
735 | }
|
---|
736 |
|
---|
737 | struct vfswrap_asys_state {
|
---|
738 | struct asys_context *asys_ctx;
|
---|
739 | struct tevent_req *req;
|
---|
740 | ssize_t ret;
|
---|
741 | int err;
|
---|
742 | SMBPROFILE_BASIC_ASYNC_STATE(profile_basic);
|
---|
743 | SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
|
---|
744 | };
|
---|
745 |
|
---|
746 | static int vfswrap_asys_state_destructor(struct vfswrap_asys_state *s)
|
---|
747 | {
|
---|
748 | asys_cancel(s->asys_ctx, s->req);
|
---|
749 | return 0;
|
---|
750 | }
|
---|
751 |
|
---|
752 | static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
|
---|
753 | TALLOC_CTX *mem_ctx,
|
---|
754 | struct tevent_context *ev,
|
---|
755 | struct files_struct *fsp,
|
---|
756 | void *data,
|
---|
757 | size_t n, off_t offset)
|
---|
758 | {
|
---|
759 | struct tevent_req *req;
|
---|
760 | struct vfswrap_asys_state *state;
|
---|
761 | int ret;
|
---|
762 |
|
---|
763 | req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
|
---|
764 | if (req == NULL) {
|
---|
765 | return NULL;
|
---|
766 | }
|
---|
767 | if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
|
---|
768 | tevent_req_oom(req);
|
---|
769 | return tevent_req_post(req, ev);
|
---|
770 | }
|
---|
771 | state->asys_ctx = handle->conn->sconn->asys_ctx;
|
---|
772 | state->req = req;
|
---|
773 |
|
---|
774 | SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
|
---|
775 | state->profile_bytes, n);
|
---|
776 | ret = asys_pread(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
|
---|
777 | if (ret != 0) {
|
---|
778 | tevent_req_error(req, ret);
|
---|
779 | return tevent_req_post(req, ev);
|
---|
780 | }
|
---|
781 | talloc_set_destructor(state, vfswrap_asys_state_destructor);
|
---|
782 |
|
---|
783 | return req;
|
---|
784 | }
|
---|
785 |
|
---|
786 | static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
|
---|
787 | TALLOC_CTX *mem_ctx,
|
---|
788 | struct tevent_context *ev,
|
---|
789 | struct files_struct *fsp,
|
---|
790 | const void *data,
|
---|
791 | size_t n, off_t offset)
|
---|
792 | {
|
---|
793 | struct tevent_req *req;
|
---|
794 | struct vfswrap_asys_state *state;
|
---|
795 | int ret;
|
---|
796 |
|
---|
797 | req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
|
---|
798 | if (req == NULL) {
|
---|
799 | return NULL;
|
---|
800 | }
|
---|
801 | if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
|
---|
802 | tevent_req_oom(req);
|
---|
803 | return tevent_req_post(req, ev);
|
---|
804 | }
|
---|
805 | state->asys_ctx = handle->conn->sconn->asys_ctx;
|
---|
806 | state->req = req;
|
---|
807 |
|
---|
808 | SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
|
---|
809 | state->profile_bytes, n);
|
---|
810 | ret = asys_pwrite(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
|
---|
811 | if (ret != 0) {
|
---|
812 | tevent_req_error(req, ret);
|
---|
813 | return tevent_req_post(req, ev);
|
---|
814 | }
|
---|
815 | talloc_set_destructor(state, vfswrap_asys_state_destructor);
|
---|
816 |
|
---|
817 | return req;
|
---|
818 | }
|
---|
819 |
|
---|
820 | static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
|
---|
821 | TALLOC_CTX *mem_ctx,
|
---|
822 | struct tevent_context *ev,
|
---|
823 | struct files_struct *fsp)
|
---|
824 | {
|
---|
825 | struct tevent_req *req;
|
---|
826 | struct vfswrap_asys_state *state;
|
---|
827 | int ret;
|
---|
828 |
|
---|
829 | req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
|
---|
830 | if (req == NULL) {
|
---|
831 | return NULL;
|
---|
832 | }
|
---|
833 | if (!vfswrap_init_asys_ctx(handle->conn->sconn)) {
|
---|
834 | tevent_req_oom(req);
|
---|
835 | return tevent_req_post(req, ev);
|
---|
836 | }
|
---|
837 | state->asys_ctx = handle->conn->sconn->asys_ctx;
|
---|
838 | state->req = req;
|
---|
839 |
|
---|
840 | SMBPROFILE_BASIC_ASYNC_START(syscall_asys_fsync, profile_p,
|
---|
841 | state->profile_basic);
|
---|
842 | ret = asys_fsync(state->asys_ctx, fsp->fh->fd, req);
|
---|
843 | if (ret != 0) {
|
---|
844 | tevent_req_error(req, ret);
|
---|
845 | return tevent_req_post(req, ev);
|
---|
846 | }
|
---|
847 | talloc_set_destructor(state, vfswrap_asys_state_destructor);
|
---|
848 |
|
---|
849 | return req;
|
---|
850 | }
|
---|
851 |
|
---|
852 | static void vfswrap_asys_finished(struct tevent_context *ev,
|
---|
853 | struct tevent_fd *fde,
|
---|
854 | uint16_t flags, void *p)
|
---|
855 | {
|
---|
856 | struct asys_context *asys_ctx = (struct asys_context *)p;
|
---|
857 | struct asys_result results[get_outstanding_aio_calls()];
|
---|
858 | int i, ret;
|
---|
859 |
|
---|
860 | if ((flags & TEVENT_FD_READ) == 0) {
|
---|
861 | return;
|
---|
862 | }
|
---|
863 |
|
---|
864 | ret = asys_results(asys_ctx, results, get_outstanding_aio_calls());
|
---|
865 | if (ret < 0) {
|
---|
866 | DEBUG(1, ("asys_results returned %s\n", strerror(-ret)));
|
---|
867 | return;
|
---|
868 | }
|
---|
869 |
|
---|
870 | for (i=0; i<ret; i++) {
|
---|
871 | struct asys_result *result = &results[i];
|
---|
872 | struct tevent_req *req;
|
---|
873 | struct vfswrap_asys_state *state;
|
---|
874 |
|
---|
875 | if ((result->ret == -1) && (result->err == ECANCELED)) {
|
---|
876 | continue;
|
---|
877 | }
|
---|
878 |
|
---|
879 | req = talloc_get_type_abort(result->private_data,
|
---|
880 | struct tevent_req);
|
---|
881 | state = tevent_req_data(req, struct vfswrap_asys_state);
|
---|
882 |
|
---|
883 | talloc_set_destructor(state, NULL);
|
---|
884 |
|
---|
885 | SMBPROFILE_BASIC_ASYNC_END(state->profile_basic);
|
---|
886 | SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
|
---|
887 | state->ret = result->ret;
|
---|
888 | state->err = result->err;
|
---|
889 | tevent_req_defer_callback(req, ev);
|
---|
890 | tevent_req_done(req);
|
---|
891 | }
|
---|
892 | }
|
---|
893 |
|
---|
894 | static ssize_t vfswrap_asys_ssize_t_recv(struct tevent_req *req, int *err)
|
---|
895 | {
|
---|
896 | struct vfswrap_asys_state *state = tevent_req_data(
|
---|
897 | req, struct vfswrap_asys_state);
|
---|
898 |
|
---|
899 | if (tevent_req_is_unix_error(req, err)) {
|
---|
900 | return -1;
|
---|
901 | }
|
---|
902 | *err = state->err;
|
---|
903 | return state->ret;
|
---|
904 | }
|
---|
905 |
|
---|
906 | static int vfswrap_asys_int_recv(struct tevent_req *req, int *err)
|
---|
907 | {
|
---|
908 | struct vfswrap_asys_state *state = tevent_req_data(
|
---|
909 | req, struct vfswrap_asys_state);
|
---|
910 |
|
---|
911 | if (tevent_req_is_unix_error(req, err)) {
|
---|
912 | return -1;
|
---|
913 | }
|
---|
914 | *err = state->err;
|
---|
915 | return state->ret;
|
---|
916 | }
|
---|
917 |
|
---|
918 | static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
|
---|
919 | {
|
---|
920 | off_t result = 0;
|
---|
921 |
|
---|
922 | START_PROFILE(syscall_lseek);
|
---|
923 |
|
---|
924 | /* Cope with 'stat' file opens. */
|
---|
925 | if (fsp->fh->fd != -1)
|
---|
926 | result = lseek(fsp->fh->fd, offset, whence);
|
---|
927 |
|
---|
928 | /*
|
---|
929 | * We want to maintain the fiction that we can seek
|
---|
930 | * on a fifo for file system purposes. This allows
|
---|
931 | * people to set up UNIX fifo's that feed data to Windows
|
---|
932 | * applications. JRA.
|
---|
933 | */
|
---|
934 |
|
---|
935 | if((result == -1) && (errno == ESPIPE)) {
|
---|
936 | result = 0;
|
---|
937 | errno = 0;
|
---|
938 | }
|
---|
939 |
|
---|
940 | END_PROFILE(syscall_lseek);
|
---|
941 | return result;
|
---|
942 | }
|
---|
943 |
|
---|
944 | static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
|
---|
945 | off_t offset, size_t n)
|
---|
946 | {
|
---|
947 | ssize_t result;
|
---|
948 |
|
---|
949 | START_PROFILE_BYTES(syscall_sendfile, n);
|
---|
950 | result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
|
---|
951 | END_PROFILE_BYTES(syscall_sendfile);
|
---|
952 | return result;
|
---|
953 | }
|
---|
954 |
|
---|
955 | static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
|
---|
956 | int fromfd,
|
---|
957 | files_struct *tofsp,
|
---|
958 | off_t offset,
|
---|
959 | size_t n)
|
---|
960 | {
|
---|
961 | ssize_t result;
|
---|
962 |
|
---|
963 | START_PROFILE_BYTES(syscall_recvfile, n);
|
---|
964 | result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
|
---|
965 | END_PROFILE_BYTES(syscall_recvfile);
|
---|
966 | return result;
|
---|
967 | }
|
---|
968 |
|
---|
969 | static int vfswrap_rename(vfs_handle_struct *handle,
|
---|
970 | const struct smb_filename *smb_fname_src,
|
---|
971 | const struct smb_filename *smb_fname_dst)
|
---|
972 | {
|
---|
973 | int result = -1;
|
---|
974 |
|
---|
975 | START_PROFILE(syscall_rename);
|
---|
976 |
|
---|
977 | if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
|
---|
978 | errno = ENOENT;
|
---|
979 | goto out;
|
---|
980 | }
|
---|
981 |
|
---|
982 | result = rename(smb_fname_src->base_name, smb_fname_dst->base_name);
|
---|
983 |
|
---|
984 | out:
|
---|
985 | END_PROFILE(syscall_rename);
|
---|
986 | return result;
|
---|
987 | }
|
---|
988 |
|
---|
989 | static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp)
|
---|
990 | {
|
---|
991 | #ifdef HAVE_FSYNC
|
---|
992 | int result;
|
---|
993 |
|
---|
994 | START_PROFILE(syscall_fsync);
|
---|
995 | result = fsync(fsp->fh->fd);
|
---|
996 | END_PROFILE(syscall_fsync);
|
---|
997 | return result;
|
---|
998 | #else
|
---|
999 | return 0;
|
---|
1000 | #endif
|
---|
1001 | }
|
---|
1002 |
|
---|
1003 | static int vfswrap_stat(vfs_handle_struct *handle,
|
---|
1004 | struct smb_filename *smb_fname)
|
---|
1005 | {
|
---|
1006 | int result = -1;
|
---|
1007 |
|
---|
1008 | START_PROFILE(syscall_stat);
|
---|
1009 |
|
---|
1010 | if (smb_fname->stream_name) {
|
---|
1011 | errno = ENOENT;
|
---|
1012 | goto out;
|
---|
1013 | }
|
---|
1014 |
|
---|
1015 | result = sys_stat(smb_fname->base_name, &smb_fname->st,
|
---|
1016 | lp_fake_directory_create_times(SNUM(handle->conn)));
|
---|
1017 | out:
|
---|
1018 | END_PROFILE(syscall_stat);
|
---|
1019 | return result;
|
---|
1020 | }
|
---|
1021 |
|
---|
1022 | static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
|
---|
1023 | {
|
---|
1024 | int result;
|
---|
1025 |
|
---|
1026 | START_PROFILE(syscall_fstat);
|
---|
1027 | result = sys_fstat(fsp->fh->fd,
|
---|
1028 | sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
|
---|
1029 | END_PROFILE(syscall_fstat);
|
---|
1030 | return result;
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 | static int vfswrap_lstat(vfs_handle_struct *handle,
|
---|
1034 | struct smb_filename *smb_fname)
|
---|
1035 | {
|
---|
1036 | int result = -1;
|
---|
1037 |
|
---|
1038 | START_PROFILE(syscall_lstat);
|
---|
1039 |
|
---|
1040 | if (smb_fname->stream_name) {
|
---|
1041 | errno = ENOENT;
|
---|
1042 | goto out;
|
---|
1043 | }
|
---|
1044 |
|
---|
1045 | result = sys_lstat(smb_fname->base_name, &smb_fname->st,
|
---|
1046 | lp_fake_directory_create_times(SNUM(handle->conn)));
|
---|
1047 | out:
|
---|
1048 | END_PROFILE(syscall_lstat);
|
---|
1049 | return result;
|
---|
1050 | }
|
---|
1051 |
|
---|
1052 | static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
|
---|
1053 | const char *name,
|
---|
1054 | enum vfs_translate_direction direction,
|
---|
1055 | TALLOC_CTX *mem_ctx,
|
---|
1056 | char **mapped_name)
|
---|
1057 | {
|
---|
1058 | return NT_STATUS_NONE_MAPPED;
|
---|
1059 | }
|
---|
1060 |
|
---|
1061 | /*
|
---|
1062 | * Implement the default fsctl operation.
|
---|
1063 | */
|
---|
1064 | static bool vfswrap_logged_ioctl_message = false;
|
---|
1065 |
|
---|
1066 | static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
|
---|
1067 | struct files_struct *fsp,
|
---|
1068 | TALLOC_CTX *ctx,
|
---|
1069 | uint32_t function,
|
---|
1070 | uint16_t req_flags, /* Needed for UNICODE ... */
|
---|
1071 | const uint8_t *_in_data,
|
---|
1072 | uint32_t in_len,
|
---|
1073 | uint8_t **_out_data,
|
---|
1074 | uint32_t max_out_len,
|
---|
1075 | uint32_t *out_len)
|
---|
1076 | {
|
---|
1077 | const char *in_data = (const char *)_in_data;
|
---|
1078 | char **out_data = (char **)_out_data;
|
---|
1079 | NTSTATUS status;
|
---|
1080 |
|
---|
1081 | switch (function) {
|
---|
1082 | case FSCTL_SET_SPARSE:
|
---|
1083 | {
|
---|
1084 | bool set_sparse = true;
|
---|
1085 |
|
---|
1086 | if (in_len >= 1 && in_data[0] == 0) {
|
---|
1087 | set_sparse = false;
|
---|
1088 | }
|
---|
1089 |
|
---|
1090 | status = file_set_sparse(handle->conn, fsp, set_sparse);
|
---|
1091 |
|
---|
1092 | DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
|
---|
1093 | ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
|
---|
1094 | smb_fname_str_dbg(fsp->fsp_name), set_sparse,
|
---|
1095 | nt_errstr(status)));
|
---|
1096 |
|
---|
1097 | return status;
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 | case FSCTL_CREATE_OR_GET_OBJECT_ID:
|
---|
1101 | {
|
---|
1102 | unsigned char objid[16];
|
---|
1103 | char *return_data = NULL;
|
---|
1104 |
|
---|
1105 | /* This should return the object-id on this file.
|
---|
1106 | * I think I'll make this be the inode+dev. JRA.
|
---|
1107 | */
|
---|
1108 |
|
---|
1109 | DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
|
---|
1110 | fsp_fnum_dbg(fsp)));
|
---|
1111 |
|
---|
1112 | *out_len = MIN(max_out_len, 64);
|
---|
1113 |
|
---|
1114 | /* Hmmm, will this cause problems if less data asked for? */
|
---|
1115 | return_data = talloc_array(ctx, char, 64);
|
---|
1116 | if (return_data == NULL) {
|
---|
1117 | return NT_STATUS_NO_MEMORY;
|
---|
1118 | }
|
---|
1119 |
|
---|
1120 | /* For backwards compatibility only store the dev/inode. */
|
---|
1121 | push_file_id_16(return_data, &fsp->file_id);
|
---|
1122 | memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
|
---|
1123 | push_file_id_16(return_data+32, &fsp->file_id);
|
---|
1124 | memset(return_data+48, 0, 16);
|
---|
1125 | *out_data = return_data;
|
---|
1126 | return NT_STATUS_OK;
|
---|
1127 | }
|
---|
1128 |
|
---|
1129 | case FSCTL_GET_REPARSE_POINT:
|
---|
1130 | {
|
---|
1131 | /* Fail it with STATUS_NOT_A_REPARSE_POINT */
|
---|
1132 | DEBUG(10, ("FSCTL_GET_REPARSE_POINT: called on %s. "
|
---|
1133 | "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
|
---|
1134 | return NT_STATUS_NOT_A_REPARSE_POINT;
|
---|
1135 | }
|
---|
1136 |
|
---|
1137 | case FSCTL_SET_REPARSE_POINT:
|
---|
1138 | {
|
---|
1139 | /* Fail it with STATUS_NOT_A_REPARSE_POINT */
|
---|
1140 | DEBUG(10, ("FSCTL_SET_REPARSE_POINT: called on %s. "
|
---|
1141 | "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
|
---|
1142 | return NT_STATUS_NOT_A_REPARSE_POINT;
|
---|
1143 | }
|
---|
1144 |
|
---|
1145 | case FSCTL_GET_SHADOW_COPY_DATA:
|
---|
1146 | {
|
---|
1147 | /*
|
---|
1148 | * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
|
---|
1149 | * and return their volume names. If max_data_count is 16, then it is just
|
---|
1150 | * asking for the number of volumes and length of the combined names.
|
---|
1151 | *
|
---|
1152 | * pdata is the data allocated by our caller, but that uses
|
---|
1153 | * total_data_count (which is 0 in our case) rather than max_data_count.
|
---|
1154 | * Allocate the correct amount and return the pointer to let
|
---|
1155 | * it be deallocated when we return.
|
---|
1156 | */
|
---|
1157 | struct shadow_copy_data *shadow_data = NULL;
|
---|
1158 | bool labels = False;
|
---|
1159 | uint32_t labels_data_count = 0;
|
---|
1160 | uint32_t i;
|
---|
1161 | char *cur_pdata = NULL;
|
---|
1162 |
|
---|
1163 | if (max_out_len < 16) {
|
---|
1164 | DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
|
---|
1165 | max_out_len));
|
---|
1166 | return NT_STATUS_INVALID_PARAMETER;
|
---|
1167 | }
|
---|
1168 |
|
---|
1169 | if (max_out_len > 16) {
|
---|
1170 | labels = True;
|
---|
1171 | }
|
---|
1172 |
|
---|
1173 | shadow_data = talloc_zero(ctx, struct shadow_copy_data);
|
---|
1174 | if (shadow_data == NULL) {
|
---|
1175 | DEBUG(0,("TALLOC_ZERO() failed!\n"));
|
---|
1176 | return NT_STATUS_NO_MEMORY;
|
---|
1177 | }
|
---|
1178 |
|
---|
1179 | /*
|
---|
1180 | * Call the VFS routine to actually do the work.
|
---|
1181 | */
|
---|
1182 | if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
|
---|
1183 | int log_lev = 0;
|
---|
1184 | if (errno == 0) {
|
---|
1185 | /* broken module didn't set errno on error */
|
---|
1186 | status = NT_STATUS_UNSUCCESSFUL;
|
---|
1187 | } else {
|
---|
1188 | status = map_nt_error_from_unix(errno);
|
---|
1189 | if (NT_STATUS_EQUAL(status,
|
---|
1190 | NT_STATUS_NOT_SUPPORTED)) {
|
---|
1191 | log_lev = 5;
|
---|
1192 | }
|
---|
1193 | }
|
---|
1194 | DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
|
---|
1195 | "connectpath %s, failed - %s.\n",
|
---|
1196 | fsp->conn->connectpath,
|
---|
1197 | nt_errstr(status)));
|
---|
1198 | TALLOC_FREE(shadow_data);
|
---|
1199 | return status;
|
---|
1200 | }
|
---|
1201 |
|
---|
1202 | labels_data_count = (shadow_data->num_volumes * 2 *
|
---|
1203 | sizeof(SHADOW_COPY_LABEL)) + 2;
|
---|
1204 |
|
---|
1205 | if (!labels) {
|
---|
1206 | *out_len = 16;
|
---|
1207 | } else {
|
---|
1208 | *out_len = 12 + labels_data_count;
|
---|
1209 | }
|
---|
1210 |
|
---|
1211 | if (max_out_len < *out_len) {
|
---|
1212 | DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
|
---|
1213 | max_out_len, *out_len));
|
---|
1214 | TALLOC_FREE(shadow_data);
|
---|
1215 | return NT_STATUS_BUFFER_TOO_SMALL;
|
---|
1216 | }
|
---|
1217 |
|
---|
1218 | cur_pdata = talloc_zero_array(ctx, char, *out_len);
|
---|
1219 | if (cur_pdata == NULL) {
|
---|
1220 | TALLOC_FREE(shadow_data);
|
---|
1221 | return NT_STATUS_NO_MEMORY;
|
---|
1222 | }
|
---|
1223 |
|
---|
1224 | *out_data = cur_pdata;
|
---|
1225 |
|
---|
1226 | /* num_volumes 4 bytes */
|
---|
1227 | SIVAL(cur_pdata, 0, shadow_data->num_volumes);
|
---|
1228 |
|
---|
1229 | if (labels) {
|
---|
1230 | /* num_labels 4 bytes */
|
---|
1231 | SIVAL(cur_pdata, 4, shadow_data->num_volumes);
|
---|
1232 | }
|
---|
1233 |
|
---|
1234 | /* needed_data_count 4 bytes */
|
---|
1235 | SIVAL(cur_pdata, 8, labels_data_count);
|
---|
1236 |
|
---|
1237 | cur_pdata += 12;
|
---|
1238 |
|
---|
1239 | DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
|
---|
1240 | shadow_data->num_volumes, fsp_str_dbg(fsp)));
|
---|
1241 | if (labels && shadow_data->labels) {
|
---|
1242 | for (i=0; i<shadow_data->num_volumes; i++) {
|
---|
1243 | size_t len = 0;
|
---|
1244 | status = srvstr_push(cur_pdata, req_flags,
|
---|
1245 | cur_pdata, shadow_data->labels[i],
|
---|
1246 | 2 * sizeof(SHADOW_COPY_LABEL),
|
---|
1247 | STR_UNICODE|STR_TERMINATE, &len);
|
---|
1248 | if (!NT_STATUS_IS_OK(status)) {
|
---|
1249 | TALLOC_FREE(*out_data);
|
---|
1250 | TALLOC_FREE(shadow_data);
|
---|
1251 | return status;
|
---|
1252 | }
|
---|
1253 | cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
|
---|
1254 | DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
|
---|
1255 | }
|
---|
1256 | }
|
---|
1257 |
|
---|
1258 | TALLOC_FREE(shadow_data);
|
---|
1259 |
|
---|
1260 | return NT_STATUS_OK;
|
---|
1261 | }
|
---|
1262 |
|
---|
1263 | case FSCTL_FIND_FILES_BY_SID:
|
---|
1264 | {
|
---|
1265 | /* pretend this succeeded -
|
---|
1266 | *
|
---|
1267 | * we have to send back a list with all files owned by this SID
|
---|
1268 | *
|
---|
1269 | * but I have to check that --metze
|
---|
1270 | */
|
---|
1271 | struct dom_sid sid;
|
---|
1272 | uid_t uid;
|
---|
1273 | size_t sid_len;
|
---|
1274 |
|
---|
1275 | DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
|
---|
1276 | fsp_fnum_dbg(fsp)));
|
---|
1277 |
|
---|
1278 | if (in_len < 8) {
|
---|
1279 | /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
|
---|
1280 | return NT_STATUS_INVALID_PARAMETER;
|
---|
1281 | }
|
---|
1282 |
|
---|
1283 | sid_len = MIN(in_len - 4,SID_MAX_SIZE);
|
---|
1284 |
|
---|
1285 | /* unknown 4 bytes: this is not the length of the sid :-( */
|
---|
1286 | /*unknown = IVAL(pdata,0);*/
|
---|
1287 |
|
---|
1288 | if (!sid_parse(_in_data + 4, sid_len, &sid)) {
|
---|
1289 | return NT_STATUS_INVALID_PARAMETER;
|
---|
1290 | }
|
---|
1291 | DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid)));
|
---|
1292 |
|
---|
1293 | if (!sid_to_uid(&sid, &uid)) {
|
---|
1294 | DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
|
---|
1295 | sid_string_dbg(&sid),
|
---|
1296 | (unsigned long)sid_len));
|
---|
1297 | uid = (-1);
|
---|
1298 | }
|
---|
1299 |
|
---|
1300 | /* we can take a look at the find source :-)
|
---|
1301 | *
|
---|
1302 | * find ./ -uid $uid -name '*' is what we need here
|
---|
1303 | *
|
---|
1304 | *
|
---|
1305 | * and send 4bytes len and then NULL terminated unicode strings
|
---|
1306 | * for each file
|
---|
1307 | *
|
---|
1308 | * but I don't know how to deal with the paged results
|
---|
1309 | * (maybe we can hang the result anywhere in the fsp struct)
|
---|
1310 | *
|
---|
1311 | * but I don't know how to deal with the paged results
|
---|
1312 | * (maybe we can hang the result anywhere in the fsp struct)
|
---|
1313 | *
|
---|
1314 | * we don't send all files at once
|
---|
1315 | * and at the next we should *not* start from the beginning,
|
---|
1316 | * so we have to cache the result
|
---|
1317 | *
|
---|
1318 | * --metze
|
---|
1319 | */
|
---|
1320 |
|
---|
1321 | /* this works for now... */
|
---|
1322 | return NT_STATUS_OK;
|
---|
1323 | }
|
---|
1324 |
|
---|
1325 | case FSCTL_QUERY_ALLOCATED_RANGES:
|
---|
1326 | {
|
---|
1327 | /* FIXME: This is just a dummy reply, telling that all of the
|
---|
1328 | * file is allocated. MKS cp needs that.
|
---|
1329 | * Adding the real allocated ranges via FIEMAP on Linux
|
---|
1330 | * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
|
---|
1331 | * this FSCTL correct for sparse files.
|
---|
1332 | */
|
---|
1333 | uint64_t offset, length;
|
---|
1334 | char *out_data_tmp = NULL;
|
---|
1335 |
|
---|
1336 | if (in_len != 16) {
|
---|
1337 | DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
|
---|
1338 | in_len));
|
---|
1339 | return NT_STATUS_INVALID_PARAMETER;
|
---|
1340 | }
|
---|
1341 |
|
---|
1342 | if (max_out_len < 16) {
|
---|
1343 | DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
|
---|
1344 | max_out_len));
|
---|
1345 | return NT_STATUS_INVALID_PARAMETER;
|
---|
1346 | }
|
---|
1347 |
|
---|
1348 | offset = BVAL(in_data,0);
|
---|
1349 | length = BVAL(in_data,8);
|
---|
1350 |
|
---|
1351 | if (offset + length < offset) {
|
---|
1352 | /* No 64-bit integer wrap. */
|
---|
1353 | return NT_STATUS_INVALID_PARAMETER;
|
---|
1354 | }
|
---|
1355 |
|
---|
1356 | /* Shouldn't this be SMB_VFS_STAT ... ? */
|
---|
1357 | status = vfs_stat_fsp(fsp);
|
---|
1358 | if (!NT_STATUS_IS_OK(status)) {
|
---|
1359 | return status;
|
---|
1360 | }
|
---|
1361 |
|
---|
1362 | *out_len = 16;
|
---|
1363 | out_data_tmp = talloc_array(ctx, char, *out_len);
|
---|
1364 | if (out_data_tmp == NULL) {
|
---|
1365 | DEBUG(10, ("unable to allocate memory for response\n"));
|
---|
1366 | return NT_STATUS_NO_MEMORY;
|
---|
1367 | }
|
---|
1368 |
|
---|
1369 | if (offset > fsp->fsp_name->st.st_ex_size ||
|
---|
1370 | fsp->fsp_name->st.st_ex_size == 0 ||
|
---|
1371 | length == 0) {
|
---|
1372 | memset(out_data_tmp, 0, *out_len);
|
---|
1373 | } else {
|
---|
1374 | uint64_t end = offset + length;
|
---|
1375 | end = MIN(end, fsp->fsp_name->st.st_ex_size);
|
---|
1376 | SBVAL(out_data_tmp, 0, 0);
|
---|
1377 | SBVAL(out_data_tmp, 8, end);
|
---|
1378 | }
|
---|
1379 |
|
---|
1380 | *out_data = out_data_tmp;
|
---|
1381 |
|
---|
1382 | return NT_STATUS_OK;
|
---|
1383 | }
|
---|
1384 |
|
---|
1385 | case FSCTL_IS_VOLUME_DIRTY:
|
---|
1386 | {
|
---|
1387 | DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
|
---|
1388 | "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
|
---|
1389 | /*
|
---|
1390 | * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
|
---|
1391 | * says we have to respond with NT_STATUS_INVALID_PARAMETER
|
---|
1392 | */
|
---|
1393 | return NT_STATUS_INVALID_PARAMETER;
|
---|
1394 | }
|
---|
1395 |
|
---|
1396 | default:
|
---|
1397 | /*
|
---|
1398 | * Only print once ... unfortunately there could be lots of
|
---|
1399 | * different FSCTLs that are called.
|
---|
1400 | */
|
---|
1401 | if (!vfswrap_logged_ioctl_message) {
|
---|
1402 | vfswrap_logged_ioctl_message = true;
|
---|
1403 | DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
|
---|
1404 | __func__, function));
|
---|
1405 | }
|
---|
1406 | }
|
---|
1407 |
|
---|
1408 | return NT_STATUS_NOT_SUPPORTED;
|
---|
1409 | }
|
---|
1410 |
|
---|
1411 | struct vfs_cc_state {
|
---|
1412 | off_t copied;
|
---|
1413 | uint8_t *buf;
|
---|
1414 | };
|
---|
1415 |
|
---|
1416 | static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *handle,
|
---|
1417 | TALLOC_CTX *mem_ctx,
|
---|
1418 | struct tevent_context *ev,
|
---|
1419 | struct files_struct *src_fsp,
|
---|
1420 | off_t src_off,
|
---|
1421 | struct files_struct *dest_fsp,
|
---|
1422 | off_t dest_off,
|
---|
1423 | off_t num)
|
---|
1424 | {
|
---|
1425 | struct tevent_req *req;
|
---|
1426 | struct vfs_cc_state *vfs_cc_state;
|
---|
1427 | NTSTATUS status;
|
---|
1428 |
|
---|
1429 | DEBUG(10, ("performing server side copy chunk of length %lu\n",
|
---|
1430 | (unsigned long)num));
|
---|
1431 |
|
---|
1432 | req = tevent_req_create(mem_ctx, &vfs_cc_state, struct vfs_cc_state);
|
---|
1433 | if (req == NULL) {
|
---|
1434 | return NULL;
|
---|
1435 | }
|
---|
1436 |
|
---|
1437 | vfs_cc_state->buf = talloc_array(vfs_cc_state, uint8_t,
|
---|
1438 | MIN(num, 8*1024*1024));
|
---|
1439 | if (tevent_req_nomem(vfs_cc_state->buf, req)) {
|
---|
1440 | return tevent_req_post(req, ev);
|
---|
1441 | }
|
---|
1442 |
|
---|
1443 | status = vfs_stat_fsp(src_fsp);
|
---|
1444 | if (tevent_req_nterror(req, status)) {
|
---|
1445 | return tevent_req_post(req, ev);
|
---|
1446 | }
|
---|
1447 |
|
---|
1448 | if (src_fsp->fsp_name->st.st_ex_size < src_off + num) {
|
---|
1449 | /*
|
---|
1450 | * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
|
---|
1451 | * If the SourceOffset or SourceOffset + Length extends beyond
|
---|
1452 | * the end of file, the server SHOULD<240> treat this as a
|
---|
1453 | * STATUS_END_OF_FILE error.
|
---|
1454 | * ...
|
---|
1455 | * <240> Section 3.3.5.15.6: Windows servers will return
|
---|
1456 | * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
|
---|
1457 | */
|
---|
1458 | tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
|
---|
1459 | return tevent_req_post(req, ev);
|
---|
1460 | }
|
---|
1461 |
|
---|
1462 | /* could use 2.6.33+ sendfile here to do this in kernel */
|
---|
1463 | while (vfs_cc_state->copied < num) {
|
---|
1464 | ssize_t ret;
|
---|
1465 | struct lock_struct lck;
|
---|
1466 | int saved_errno;
|
---|
1467 |
|
---|
1468 | off_t this_num = MIN(talloc_array_length(vfs_cc_state->buf),
|
---|
1469 | num - vfs_cc_state->copied);
|
---|
1470 |
|
---|
1471 | if (src_fsp->op == NULL) {
|
---|
1472 | tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
|
---|
1473 | return tevent_req_post(req, ev);
|
---|
1474 | }
|
---|
1475 | init_strict_lock_struct(src_fsp,
|
---|
1476 | src_fsp->op->global->open_persistent_id,
|
---|
1477 | src_off,
|
---|
1478 | this_num,
|
---|
1479 | READ_LOCK,
|
---|
1480 | &lck);
|
---|
1481 |
|
---|
1482 | if (!SMB_VFS_STRICT_LOCK(src_fsp->conn, src_fsp, &lck)) {
|
---|
1483 | tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
|
---|
1484 | return tevent_req_post(req, ev);
|
---|
1485 | }
|
---|
1486 |
|
---|
1487 | ret = SMB_VFS_PREAD(src_fsp, vfs_cc_state->buf,
|
---|
1488 | this_num, src_off);
|
---|
1489 | if (ret == -1) {
|
---|
1490 | saved_errno = errno;
|
---|
1491 | }
|
---|
1492 |
|
---|
1493 | SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &lck);
|
---|
1494 |
|
---|
1495 | if (ret == -1) {
|
---|
1496 | errno = saved_errno;
|
---|
1497 | tevent_req_nterror(req, map_nt_error_from_unix(errno));
|
---|
1498 | return tevent_req_post(req, ev);
|
---|
1499 | }
|
---|
1500 | if (ret != this_num) {
|
---|
1501 | /* zero tolerance for short reads */
|
---|
1502 | tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
|
---|
1503 | return tevent_req_post(req, ev);
|
---|
1504 | }
|
---|
1505 |
|
---|
1506 | src_off += ret;
|
---|
1507 |
|
---|
1508 | if (dest_fsp->op == NULL) {
|
---|
1509 | tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
|
---|
1510 | return tevent_req_post(req, ev);
|
---|
1511 | }
|
---|
1512 |
|
---|
1513 | init_strict_lock_struct(dest_fsp,
|
---|
1514 | dest_fsp->op->global->open_persistent_id,
|
---|
1515 | dest_off,
|
---|
1516 | this_num,
|
---|
1517 | WRITE_LOCK,
|
---|
1518 | &lck);
|
---|
1519 |
|
---|
1520 | if (!SMB_VFS_STRICT_LOCK(dest_fsp->conn, dest_fsp, &lck)) {
|
---|
1521 | tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
|
---|
1522 | return tevent_req_post(req, ev);
|
---|
1523 | }
|
---|
1524 |
|
---|
1525 | ret = SMB_VFS_PWRITE(dest_fsp, vfs_cc_state->buf,
|
---|
1526 | this_num, dest_off);
|
---|
1527 | if (ret == -1) {
|
---|
1528 | saved_errno = errno;
|
---|
1529 | }
|
---|
1530 |
|
---|
1531 | SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &lck);
|
---|
1532 |
|
---|
1533 | if (ret == -1) {
|
---|
1534 | errno = saved_errno;
|
---|
1535 | tevent_req_nterror(req, map_nt_error_from_unix(errno));
|
---|
1536 | return tevent_req_post(req, ev);
|
---|
1537 | }
|
---|
1538 | if (ret != this_num) {
|
---|
1539 | /* zero tolerance for short writes */
|
---|
1540 | tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
|
---|
1541 | return tevent_req_post(req, ev);
|
---|
1542 | }
|
---|
1543 | dest_off += ret;
|
---|
1544 |
|
---|
1545 | vfs_cc_state->copied += this_num;
|
---|
1546 | }
|
---|
1547 |
|
---|
1548 | tevent_req_done(req);
|
---|
1549 | return tevent_req_post(req, ev);
|
---|
1550 | }
|
---|
1551 |
|
---|
1552 | static NTSTATUS vfswrap_copy_chunk_recv(struct vfs_handle_struct *handle,
|
---|
1553 | struct tevent_req *req,
|
---|
1554 | off_t *copied)
|
---|
1555 | {
|
---|
1556 | struct vfs_cc_state *vfs_cc_state = tevent_req_data(req,
|
---|
1557 | struct vfs_cc_state);
|
---|
1558 | NTSTATUS status;
|
---|
1559 |
|
---|
1560 | if (tevent_req_is_nterror(req, &status)) {
|
---|
1561 | DEBUG(2, ("server side copy chunk failed: %s\n",
|
---|
1562 | nt_errstr(status)));
|
---|
1563 | *copied = 0;
|
---|
1564 | tevent_req_received(req);
|
---|
1565 | return status;
|
---|
1566 | }
|
---|
1567 |
|
---|
1568 | *copied = vfs_cc_state->copied;
|
---|
1569 | DEBUG(10, ("server side copy chunk copied %lu\n",
|
---|
1570 | (unsigned long)*copied));
|
---|
1571 | tevent_req_received(req);
|
---|
1572 |
|
---|
1573 | return NT_STATUS_OK;
|
---|
1574 | }
|
---|
1575 |
|
---|
1576 | static NTSTATUS vfswrap_get_compression(struct vfs_handle_struct *handle,
|
---|
1577 | TALLOC_CTX *mem_ctx,
|
---|
1578 | struct files_struct *fsp,
|
---|
1579 | struct smb_filename *smb_fname,
|
---|
1580 | uint16_t *_compression_fmt)
|
---|
1581 | {
|
---|
1582 | return NT_STATUS_INVALID_DEVICE_REQUEST;
|
---|
1583 | }
|
---|
1584 |
|
---|
1585 | static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
|
---|
1586 | TALLOC_CTX *mem_ctx,
|
---|
1587 | struct files_struct *fsp,
|
---|
1588 | uint16_t compression_fmt)
|
---|
1589 | {
|
---|
1590 | return NT_STATUS_INVALID_DEVICE_REQUEST;
|
---|
1591 | }
|
---|
1592 |
|
---|
1593 | /********************************************************************
|
---|
1594 | Given a stat buffer return the allocated size on disk, taking into
|
---|
1595 | account sparse files.
|
---|
1596 | ********************************************************************/
|
---|
1597 | static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
|
---|
1598 | struct files_struct *fsp,
|
---|
1599 | const SMB_STRUCT_STAT *sbuf)
|
---|
1600 | {
|
---|
1601 | uint64_t result;
|
---|
1602 |
|
---|
1603 | START_PROFILE(syscall_get_alloc_size);
|
---|
1604 |
|
---|
1605 | if(S_ISDIR(sbuf->st_ex_mode)) {
|
---|
1606 | result = 0;
|
---|
1607 | goto out;
|
---|
1608 | }
|
---|
1609 |
|
---|
1610 | #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
|
---|
1611 | /* The type of st_blocksize is blkcnt_t which *MUST* be
|
---|
1612 | signed (according to POSIX) and can be less than 64-bits.
|
---|
1613 | Ensure when we're converting to 64 bits wide we don't
|
---|
1614 | sign extend. */
|
---|
1615 | #if defined(SIZEOF_BLKCNT_T_8)
|
---|
1616 | result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
|
---|
1617 | #elif defined(SIZEOF_BLKCNT_T_4)
|
---|
1618 | {
|
---|
1619 | uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
|
---|
1620 | result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
|
---|
1621 | }
|
---|
1622 | #else
|
---|
1623 | #error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
|
---|
1624 | #endif
|
---|
1625 | if (result == 0) {
|
---|
1626 | /*
|
---|
1627 | * Some file systems do not allocate a block for very
|
---|
1628 | * small files. But for non-empty file should report a
|
---|
1629 | * positive size.
|
---|
1630 | */
|
---|
1631 |
|
---|
1632 | uint64_t filesize = get_file_size_stat(sbuf);
|
---|
1633 | if (filesize > 0) {
|
---|
1634 | result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
|
---|
1635 | }
|
---|
1636 | }
|
---|
1637 | #else
|
---|
1638 | result = get_file_size_stat(sbuf);
|
---|
1639 | #endif
|
---|
1640 |
|
---|
1641 | if (fsp && fsp->initial_allocation_size)
|
---|
1642 | result = MAX(result,fsp->initial_allocation_size);
|
---|
1643 |
|
---|
1644 | result = smb_roundup(handle->conn, result);
|
---|
1645 |
|
---|
1646 | out:
|
---|
1647 | END_PROFILE(syscall_get_alloc_size);
|
---|
1648 | return result;
|
---|
1649 | }
|
---|
1650 |
|
---|
1651 | static int vfswrap_unlink(vfs_handle_struct *handle,
|
---|
1652 | const struct smb_filename *smb_fname)
|
---|
1653 | {
|
---|
1654 | int result = -1;
|
---|
1655 |
|
---|
1656 | START_PROFILE(syscall_unlink);
|
---|
1657 |
|
---|
1658 | if (smb_fname->stream_name) {
|
---|
1659 | errno = ENOENT;
|
---|
1660 | goto out;
|
---|
1661 | }
|
---|
1662 | result = unlink(smb_fname->base_name);
|
---|
1663 |
|
---|
1664 | out:
|
---|
1665 | END_PROFILE(syscall_unlink);
|
---|
1666 | return result;
|
---|
1667 | }
|
---|
1668 |
|
---|
1669 | static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
|
---|
1670 | {
|
---|
1671 | int result;
|
---|
1672 |
|
---|
1673 | START_PROFILE(syscall_chmod);
|
---|
1674 |
|
---|
1675 | /*
|
---|
1676 | * We need to do this due to the fact that the default POSIX ACL
|
---|
1677 | * chmod modifies the ACL *mask* for the group owner, not the
|
---|
1678 | * group owner bits directly. JRA.
|
---|
1679 | */
|
---|
1680 |
|
---|
1681 |
|
---|
1682 | {
|
---|
1683 | int saved_errno = errno; /* We might get ENOSYS */
|
---|
1684 | if ((result = SMB_VFS_CHMOD_ACL(handle->conn, path, mode)) == 0) {
|
---|
1685 | END_PROFILE(syscall_chmod);
|
---|
1686 | return result;
|
---|
1687 | }
|
---|
1688 | /* Error - return the old errno. */
|
---|
1689 | errno = saved_errno;
|
---|
1690 | }
|
---|
1691 |
|
---|
1692 | result = chmod(path, mode);
|
---|
1693 | END_PROFILE(syscall_chmod);
|
---|
1694 | return result;
|
---|
1695 | }
|
---|
1696 |
|
---|
1697 | static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
|
---|
1698 | {
|
---|
1699 | int result;
|
---|
1700 |
|
---|
1701 | START_PROFILE(syscall_fchmod);
|
---|
1702 |
|
---|
1703 | /*
|
---|
1704 | * We need to do this due to the fact that the default POSIX ACL
|
---|
1705 | * chmod modifies the ACL *mask* for the group owner, not the
|
---|
1706 | * group owner bits directly. JRA.
|
---|
1707 | */
|
---|
1708 |
|
---|
1709 | {
|
---|
1710 | int saved_errno = errno; /* We might get ENOSYS */
|
---|
1711 | if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
|
---|
1712 | END_PROFILE(syscall_fchmod);
|
---|
1713 | return result;
|
---|
1714 | }
|
---|
1715 | /* Error - return the old errno. */
|
---|
1716 | errno = saved_errno;
|
---|
1717 | }
|
---|
1718 |
|
---|
1719 | #if defined(HAVE_FCHMOD)
|
---|
1720 | result = fchmod(fsp->fh->fd, mode);
|
---|
1721 | #else
|
---|
1722 | result = -1;
|
---|
1723 | errno = ENOSYS;
|
---|
1724 | #endif
|
---|
1725 |
|
---|
1726 | END_PROFILE(syscall_fchmod);
|
---|
1727 | return result;
|
---|
1728 | }
|
---|
1729 |
|
---|
1730 | static int vfswrap_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
|
---|
1731 | {
|
---|
1732 | int result;
|
---|
1733 |
|
---|
1734 | START_PROFILE(syscall_chown);
|
---|
1735 | result = chown(path, uid, gid);
|
---|
1736 | END_PROFILE(syscall_chown);
|
---|
1737 | return result;
|
---|
1738 | }
|
---|
1739 |
|
---|
1740 | static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
|
---|
1741 | {
|
---|
1742 | #ifdef HAVE_FCHOWN
|
---|
1743 | int result;
|
---|
1744 |
|
---|
1745 | START_PROFILE(syscall_fchown);
|
---|
1746 | result = fchown(fsp->fh->fd, uid, gid);
|
---|
1747 | END_PROFILE(syscall_fchown);
|
---|
1748 | return result;
|
---|
1749 | #else
|
---|
1750 | errno = ENOSYS;
|
---|
1751 | return -1;
|
---|
1752 | #endif
|
---|
1753 | }
|
---|
1754 |
|
---|
1755 | static int vfswrap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
|
---|
1756 | {
|
---|
1757 | int result;
|
---|
1758 |
|
---|
1759 | START_PROFILE(syscall_lchown);
|
---|
1760 | result = lchown(path, uid, gid);
|
---|
1761 | END_PROFILE(syscall_lchown);
|
---|
1762 | return result;
|
---|
1763 | }
|
---|
1764 |
|
---|
1765 | static int vfswrap_chdir(vfs_handle_struct *handle, const char *path)
|
---|
1766 | {
|
---|
1767 | int result;
|
---|
1768 |
|
---|
1769 | START_PROFILE(syscall_chdir);
|
---|
1770 | result = chdir(path);
|
---|
1771 | END_PROFILE(syscall_chdir);
|
---|
1772 | return result;
|
---|
1773 | }
|
---|
1774 |
|
---|
1775 | static char *vfswrap_getwd(vfs_handle_struct *handle)
|
---|
1776 | {
|
---|
1777 | char *result;
|
---|
1778 |
|
---|
1779 | START_PROFILE(syscall_getwd);
|
---|
1780 | result = sys_getwd();
|
---|
1781 | END_PROFILE(syscall_getwd);
|
---|
1782 | return result;
|
---|
1783 | }
|
---|
1784 |
|
---|
1785 | /*********************************************************************
|
---|
1786 | nsec timestamp resolution call. Convert down to whatever the underlying
|
---|
1787 | system will support.
|
---|
1788 | **********************************************************************/
|
---|
1789 |
|
---|
1790 | static int vfswrap_ntimes(vfs_handle_struct *handle,
|
---|
1791 | const struct smb_filename *smb_fname,
|
---|
1792 | struct smb_file_time *ft)
|
---|
1793 | {
|
---|
1794 | int result = -1;
|
---|
1795 |
|
---|
1796 | START_PROFILE(syscall_ntimes);
|
---|
1797 |
|
---|
1798 | if (smb_fname->stream_name) {
|
---|
1799 | errno = ENOENT;
|
---|
1800 | goto out;
|
---|
1801 | }
|
---|
1802 |
|
---|
1803 | if (ft != NULL) {
|
---|
1804 | if (null_timespec(ft->atime)) {
|
---|
1805 | ft->atime= smb_fname->st.st_ex_atime;
|
---|
1806 | }
|
---|
1807 |
|
---|
1808 | if (null_timespec(ft->mtime)) {
|
---|
1809 | ft->mtime = smb_fname->st.st_ex_mtime;
|
---|
1810 | }
|
---|
1811 |
|
---|
1812 | if (!null_timespec(ft->create_time)) {
|
---|
1813 | set_create_timespec_ea(handle->conn,
|
---|
1814 | smb_fname,
|
---|
1815 | ft->create_time);
|
---|
1816 | }
|
---|
1817 |
|
---|
1818 | if ((timespec_compare(&ft->atime,
|
---|
1819 | &smb_fname->st.st_ex_atime) == 0) &&
|
---|
1820 | (timespec_compare(&ft->mtime,
|
---|
1821 | &smb_fname->st.st_ex_mtime) == 0)) {
|
---|
1822 | return 0;
|
---|
1823 | }
|
---|
1824 | }
|
---|
1825 |
|
---|
1826 | #if defined(HAVE_UTIMENSAT)
|
---|
1827 | if (ft != NULL) {
|
---|
1828 | struct timespec ts[2];
|
---|
1829 | ts[0] = ft->atime;
|
---|
1830 | ts[1] = ft->mtime;
|
---|
1831 | result = utimensat(AT_FDCWD, smb_fname->base_name, ts, 0);
|
---|
1832 | } else {
|
---|
1833 | result = utimensat(AT_FDCWD, smb_fname->base_name, NULL, 0);
|
---|
1834 | }
|
---|
1835 | if (!((result == -1) && (errno == ENOSYS))) {
|
---|
1836 | goto out;
|
---|
1837 | }
|
---|
1838 | #endif
|
---|
1839 | #if defined(HAVE_UTIMES)
|
---|
1840 | if (ft != NULL) {
|
---|
1841 | struct timeval tv[2];
|
---|
1842 | tv[0] = convert_timespec_to_timeval(ft->atime);
|
---|
1843 | tv[1] = convert_timespec_to_timeval(ft->mtime);
|
---|
1844 | result = utimes(smb_fname->base_name, tv);
|
---|
1845 | } else {
|
---|
1846 | result = utimes(smb_fname->base_name, NULL);
|
---|
1847 | }
|
---|
1848 | if (!((result == -1) && (errno == ENOSYS))) {
|
---|
1849 | goto out;
|
---|
1850 | }
|
---|
1851 | #endif
|
---|
1852 | #if defined(HAVE_UTIME)
|
---|
1853 | if (ft != NULL) {
|
---|
1854 | struct utimbuf times;
|
---|
1855 | times.actime = convert_timespec_to_time_t(ft->atime);
|
---|
1856 | times.modtime = convert_timespec_to_time_t(ft->mtime);
|
---|
1857 | result = utime(smb_fname->base_name, ×);
|
---|
1858 | } else {
|
---|
1859 | result = utime(smb_fname->base_name, NULL);
|
---|
1860 | }
|
---|
1861 | if (!((result == -1) && (errno == ENOSYS))) {
|
---|
1862 | goto out;
|
---|
1863 | }
|
---|
1864 | #endif
|
---|
1865 | errno = ENOSYS;
|
---|
1866 | result = -1;
|
---|
1867 |
|
---|
1868 | out:
|
---|
1869 | END_PROFILE(syscall_ntimes);
|
---|
1870 | return result;
|
---|
1871 | }
|
---|
1872 |
|
---|
1873 | /*********************************************************************
|
---|
1874 | A version of ftruncate that will write the space on disk if strict
|
---|
1875 | allocate is set.
|
---|
1876 | **********************************************************************/
|
---|
1877 |
|
---|
1878 | static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
|
---|
1879 | {
|
---|
1880 | off_t space_to_write;
|
---|
1881 | uint64_t space_avail;
|
---|
1882 | uint64_t bsize,dfree,dsize;
|
---|
1883 | int ret;
|
---|
1884 | NTSTATUS status;
|
---|
1885 | SMB_STRUCT_STAT *pst;
|
---|
1886 |
|
---|
1887 | status = vfs_stat_fsp(fsp);
|
---|
1888 | if (!NT_STATUS_IS_OK(status)) {
|
---|
1889 | return -1;
|
---|
1890 | }
|
---|
1891 | pst = &fsp->fsp_name->st;
|
---|
1892 |
|
---|
1893 | #ifdef S_ISFIFO
|
---|
1894 | if (S_ISFIFO(pst->st_ex_mode))
|
---|
1895 | return 0;
|
---|
1896 | #endif
|
---|
1897 |
|
---|
1898 | if (pst->st_ex_size == len)
|
---|
1899 | return 0;
|
---|
1900 |
|
---|
1901 | /* Shrink - just ftruncate. */
|
---|
1902 | if (pst->st_ex_size > len)
|
---|
1903 | return ftruncate(fsp->fh->fd, len);
|
---|
1904 |
|
---|
1905 | space_to_write = len - pst->st_ex_size;
|
---|
1906 |
|
---|
1907 | /* for allocation try fallocate first. This can fail on some
|
---|
1908 | platforms e.g. when the filesystem doesn't support it and no
|
---|
1909 | emulation is being done by the libc (like on AIX with JFS1). In that
|
---|
1910 | case we do our own emulation. fallocate implementations can
|
---|
1911 | return ENOTSUP or EINVAL in cases like that. */
|
---|
1912 | ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
|
---|
1913 | if (ret == -1 && errno == ENOSPC) {
|
---|
1914 | return -1;
|
---|
1915 | }
|
---|
1916 | if (ret == 0) {
|
---|
1917 | return 0;
|
---|
1918 | }
|
---|
1919 | DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
|
---|
1920 | "error %d. Falling back to slow manual allocation\n", errno));
|
---|
1921 |
|
---|
1922 | /* available disk space is enough or not? */
|
---|
1923 | space_avail =
|
---|
1924 | get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
|
---|
1925 | /* space_avail is 1k blocks */
|
---|
1926 | if (space_avail == (uint64_t)-1 ||
|
---|
1927 | ((uint64_t)space_to_write/1024 > space_avail) ) {
|
---|
1928 | errno = ENOSPC;
|
---|
1929 | return -1;
|
---|
1930 | }
|
---|
1931 |
|
---|
1932 | /* Write out the real space on disk. */
|
---|
1933 | ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
|
---|
1934 | if (ret != 0) {
|
---|
1935 | return -1;
|
---|
1936 | }
|
---|
1937 |
|
---|
1938 | return 0;
|
---|
1939 | }
|
---|
1940 |
|
---|
1941 | static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
|
---|
1942 | {
|
---|
1943 | int result = -1;
|
---|
1944 | SMB_STRUCT_STAT *pst;
|
---|
1945 | NTSTATUS status;
|
---|
1946 | char c = 0;
|
---|
1947 |
|
---|
1948 | START_PROFILE(syscall_ftruncate);
|
---|
1949 |
|
---|
1950 | if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->is_sparse) {
|
---|
1951 | result = strict_allocate_ftruncate(handle, fsp, len);
|
---|
1952 | END_PROFILE(syscall_ftruncate);
|
---|
1953 | return result;
|
---|
1954 | }
|
---|
1955 |
|
---|
1956 | /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
|
---|
1957 | ftruncate if the system supports it. Then I discovered that
|
---|
1958 | you can have some filesystems that support ftruncate
|
---|
1959 | expansion and some that don't! On Linux fat can't do
|
---|
1960 | ftruncate extend but ext2 can. */
|
---|
1961 |
|
---|
1962 | result = ftruncate(fsp->fh->fd, len);
|
---|
1963 |
|
---|
1964 | /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
|
---|
1965 | extend a file with ftruncate. Provide alternate implementation
|
---|
1966 | for this */
|
---|
1967 |
|
---|
1968 | /* Do an fstat to see if the file is longer than the requested
|
---|
1969 | size in which case the ftruncate above should have
|
---|
1970 | succeeded or shorter, in which case seek to len - 1 and
|
---|
1971 | write 1 byte of zero */
|
---|
1972 | status = vfs_stat_fsp(fsp);
|
---|
1973 | if (!NT_STATUS_IS_OK(status)) {
|
---|
1974 | goto done;
|
---|
1975 | }
|
---|
1976 |
|
---|
1977 | /* We need to update the files_struct after successful ftruncate */
|
---|
1978 | if (result == 0) {
|
---|
1979 | goto done;
|
---|
1980 | }
|
---|
1981 |
|
---|
1982 | pst = &fsp->fsp_name->st;
|
---|
1983 |
|
---|
1984 | #ifdef S_ISFIFO
|
---|
1985 | if (S_ISFIFO(pst->st_ex_mode)) {
|
---|
1986 | result = 0;
|
---|
1987 | goto done;
|
---|
1988 | }
|
---|
1989 | #endif
|
---|
1990 |
|
---|
1991 | if (pst->st_ex_size == len) {
|
---|
1992 | result = 0;
|
---|
1993 | goto done;
|
---|
1994 | }
|
---|
1995 |
|
---|
1996 | if (pst->st_ex_size > len) {
|
---|
1997 | /* the ftruncate should have worked */
|
---|
1998 | goto done;
|
---|
1999 | }
|
---|
2000 |
|
---|
2001 | if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
|
---|
2002 | goto done;
|
---|
2003 | }
|
---|
2004 |
|
---|
2005 | result = 0;
|
---|
2006 |
|
---|
2007 | done:
|
---|
2008 |
|
---|
2009 | END_PROFILE(syscall_ftruncate);
|
---|
2010 | return result;
|
---|
2011 | }
|
---|
2012 |
|
---|
2013 | static int vfswrap_fallocate(vfs_handle_struct *handle,
|
---|
2014 | files_struct *fsp,
|
---|
2015 | uint32_t mode,
|
---|
2016 | off_t offset,
|
---|
2017 | off_t len)
|
---|
2018 | {
|
---|
2019 | int result;
|
---|
2020 |
|
---|
2021 | START_PROFILE(syscall_fallocate);
|
---|
2022 | if (mode == 0) {
|
---|
2023 | result = sys_posix_fallocate(fsp->fh->fd, offset, len);
|
---|
2024 | /*
|
---|
2025 | * posix_fallocate returns 0 on success, errno on error
|
---|
2026 | * and doesn't set errno. Make it behave like fallocate()
|
---|
2027 | * which returns -1, and sets errno on failure.
|
---|
2028 | */
|
---|
2029 | if (result != 0) {
|
---|
2030 | errno = result;
|
---|
2031 | result = -1;
|
---|
2032 | }
|
---|
2033 | } else {
|
---|
2034 | /* sys_fallocate handles filtering of unsupported mode flags */
|
---|
2035 | result = sys_fallocate(fsp->fh->fd, mode, offset, len);
|
---|
2036 | }
|
---|
2037 | END_PROFILE(syscall_fallocate);
|
---|
2038 | return result;
|
---|
2039 | }
|
---|
2040 |
|
---|
2041 | static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
|
---|
2042 | {
|
---|
2043 | bool result;
|
---|
2044 |
|
---|
2045 | START_PROFILE(syscall_fcntl_lock);
|
---|
2046 | result = fcntl_lock(fsp->fh->fd, op, offset, count, type);
|
---|
2047 | END_PROFILE(syscall_fcntl_lock);
|
---|
2048 | return result;
|
---|
2049 | }
|
---|
2050 |
|
---|
2051 | static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
|
---|
2052 | uint32_t share_mode, uint32_t access_mask)
|
---|
2053 | {
|
---|
2054 | START_PROFILE(syscall_kernel_flock);
|
---|
2055 | kernel_flock(fsp->fh->fd, share_mode, access_mask);
|
---|
2056 | END_PROFILE(syscall_kernel_flock);
|
---|
2057 | return 0;
|
---|
2058 | }
|
---|
2059 |
|
---|
2060 | static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
|
---|
2061 | {
|
---|
2062 | bool result;
|
---|
2063 |
|
---|
2064 | START_PROFILE(syscall_fcntl_getlock);
|
---|
2065 | result = fcntl_getlock(fsp->fh->fd, poffset, pcount, ptype, ppid);
|
---|
2066 | END_PROFILE(syscall_fcntl_getlock);
|
---|
2067 | return result;
|
---|
2068 | }
|
---|
2069 |
|
---|
2070 | static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
|
---|
2071 | int leasetype)
|
---|
2072 | {
|
---|
2073 | int result = -1;
|
---|
2074 |
|
---|
2075 | START_PROFILE(syscall_linux_setlease);
|
---|
2076 |
|
---|
2077 | #ifdef HAVE_KERNEL_OPLOCKS_LINUX
|
---|
2078 | result = linux_setlease(fsp->fh->fd, leasetype);
|
---|
2079 | #else
|
---|
2080 | errno = ENOSYS;
|
---|
2081 | #endif
|
---|
2082 | END_PROFILE(syscall_linux_setlease);
|
---|
2083 | return result;
|
---|
2084 | }
|
---|
2085 |
|
---|
2086 | static int vfswrap_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
|
---|
2087 | {
|
---|
2088 | int result;
|
---|
2089 |
|
---|
2090 | START_PROFILE(syscall_symlink);
|
---|
2091 | result = symlink(oldpath, newpath);
|
---|
2092 | END_PROFILE(syscall_symlink);
|
---|
2093 | return result;
|
---|
2094 | }
|
---|
2095 |
|
---|
2096 | static int vfswrap_readlink(vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
|
---|
2097 | {
|
---|
2098 | int result;
|
---|
2099 |
|
---|
2100 | START_PROFILE(syscall_readlink);
|
---|
2101 | result = readlink(path, buf, bufsiz);
|
---|
2102 | END_PROFILE(syscall_readlink);
|
---|
2103 | return result;
|
---|
2104 | }
|
---|
2105 |
|
---|
2106 | static int vfswrap_link(vfs_handle_struct *handle, const char *oldpath, const char *newpath)
|
---|
2107 | {
|
---|
2108 | int result;
|
---|
2109 |
|
---|
2110 | START_PROFILE(syscall_link);
|
---|
2111 | result = link(oldpath, newpath);
|
---|
2112 | END_PROFILE(syscall_link);
|
---|
2113 | return result;
|
---|
2114 | }
|
---|
2115 |
|
---|
2116 | static int vfswrap_mknod(vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
|
---|
2117 | {
|
---|
2118 | int result;
|
---|
2119 |
|
---|
2120 | START_PROFILE(syscall_mknod);
|
---|
2121 | result = sys_mknod(pathname, mode, dev);
|
---|
2122 | END_PROFILE(syscall_mknod);
|
---|
2123 | return result;
|
---|
2124 | }
|
---|
2125 |
|
---|
2126 | static char *vfswrap_realpath(vfs_handle_struct *handle, const char *path)
|
---|
2127 | {
|
---|
2128 | char *result;
|
---|
2129 |
|
---|
2130 | START_PROFILE(syscall_realpath);
|
---|
2131 | #ifdef REALPATH_TAKES_NULL
|
---|
2132 | result = realpath(path, NULL);
|
---|
2133 | #else
|
---|
2134 | result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
|
---|
2135 | if (result) {
|
---|
2136 | char *resolved_path = realpath(path, result);
|
---|
2137 | if (!resolved_path) {
|
---|
2138 | SAFE_FREE(result);
|
---|
2139 | } else {
|
---|
2140 | /* SMB_ASSERT(result == resolved_path) ? */
|
---|
2141 | result = resolved_path;
|
---|
2142 | }
|
---|
2143 | }
|
---|
2144 | #endif
|
---|
2145 | END_PROFILE(syscall_realpath);
|
---|
2146 | return result;
|
---|
2147 | }
|
---|
2148 |
|
---|
2149 | static int vfswrap_chflags(vfs_handle_struct *handle, const char *path,
|
---|
2150 | unsigned int flags)
|
---|
2151 | {
|
---|
2152 | #ifdef HAVE_CHFLAGS
|
---|
2153 | return chflags(path, flags);
|
---|
2154 | #else
|
---|
2155 | errno = ENOSYS;
|
---|
2156 | return -1;
|
---|
2157 | #endif
|
---|
2158 | }
|
---|
2159 |
|
---|
2160 | static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
|
---|
2161 | const SMB_STRUCT_STAT *sbuf)
|
---|
2162 | {
|
---|
2163 | struct file_id key;
|
---|
2164 |
|
---|
2165 | /* the ZERO_STRUCT ensures padding doesn't break using the key as a
|
---|
2166 | * blob */
|
---|
2167 | ZERO_STRUCT(key);
|
---|
2168 |
|
---|
2169 | key.devid = sbuf->st_ex_dev;
|
---|
2170 | key.inode = sbuf->st_ex_ino;
|
---|
2171 | /* key.extid is unused by default. */
|
---|
2172 |
|
---|
2173 | return key;
|
---|
2174 | }
|
---|
2175 |
|
---|
2176 | static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
|
---|
2177 | struct files_struct *fsp,
|
---|
2178 | const char *fname,
|
---|
2179 | TALLOC_CTX *mem_ctx,
|
---|
2180 | unsigned int *pnum_streams,
|
---|
2181 | struct stream_struct **pstreams)
|
---|
2182 | {
|
---|
2183 | SMB_STRUCT_STAT sbuf;
|
---|
2184 | struct stream_struct *tmp_streams = NULL;
|
---|
2185 | int ret;
|
---|
2186 |
|
---|
2187 | if ((fsp != NULL) && (fsp->is_directory)) {
|
---|
2188 | /*
|
---|
2189 | * No default streams on directories
|
---|
2190 | */
|
---|
2191 | goto done;
|
---|
2192 | }
|
---|
2193 |
|
---|
2194 | if ((fsp != NULL) && (fsp->fh->fd != -1)) {
|
---|
2195 | ret = SMB_VFS_FSTAT(fsp, &sbuf);
|
---|
2196 | }
|
---|
2197 | else {
|
---|
2198 | struct smb_filename smb_fname;
|
---|
2199 |
|
---|
2200 | ZERO_STRUCT(smb_fname);
|
---|
2201 | smb_fname.base_name = discard_const_p(char, fname);
|
---|
2202 |
|
---|
2203 | if (lp_posix_pathnames()) {
|
---|
2204 | ret = SMB_VFS_LSTAT(handle->conn, &smb_fname);
|
---|
2205 | } else {
|
---|
2206 | ret = SMB_VFS_STAT(handle->conn, &smb_fname);
|
---|
2207 | }
|
---|
2208 | sbuf = smb_fname.st;
|
---|
2209 | }
|
---|
2210 |
|
---|
2211 | if (ret == -1) {
|
---|
2212 | return map_nt_error_from_unix(errno);
|
---|
2213 | }
|
---|
2214 |
|
---|
2215 | if (S_ISDIR(sbuf.st_ex_mode)) {
|
---|
2216 | goto done;
|
---|
2217 | }
|
---|
2218 |
|
---|
2219 | tmp_streams = talloc_realloc(mem_ctx, *pstreams, struct stream_struct,
|
---|
2220 | (*pnum_streams) + 1);
|
---|
2221 | if (tmp_streams == NULL) {
|
---|
2222 | return NT_STATUS_NO_MEMORY;
|
---|
2223 | }
|
---|
2224 | tmp_streams[*pnum_streams].name = talloc_strdup(tmp_streams, "::$DATA");
|
---|
2225 | if (tmp_streams[*pnum_streams].name == NULL) {
|
---|
2226 | return NT_STATUS_NO_MEMORY;
|
---|
2227 | }
|
---|
2228 | tmp_streams[*pnum_streams].size = sbuf.st_ex_size;
|
---|
2229 | tmp_streams[*pnum_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp, &sbuf);
|
---|
2230 |
|
---|
2231 | *pnum_streams += 1;
|
---|
2232 | *pstreams = tmp_streams;
|
---|
2233 | done:
|
---|
2234 | return NT_STATUS_OK;
|
---|
2235 | }
|
---|
2236 |
|
---|
2237 | static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
|
---|
2238 | const char *path,
|
---|
2239 | const char *name,
|
---|
2240 | TALLOC_CTX *mem_ctx,
|
---|
2241 | char **found_name)
|
---|
2242 | {
|
---|
2243 | /*
|
---|
2244 | * Don't fall back to get_real_filename so callers can differentiate
|
---|
2245 | * between a full directory scan and an actual case-insensitive stat.
|
---|
2246 | */
|
---|
2247 | errno = EOPNOTSUPP;
|
---|
2248 | return -1;
|
---|
2249 | }
|
---|
2250 |
|
---|
2251 | static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
|
---|
2252 | const char *fname)
|
---|
2253 | {
|
---|
2254 | return handle->conn->connectpath;
|
---|
2255 | }
|
---|
2256 |
|
---|
2257 | static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
|
---|
2258 | struct byte_range_lock *br_lck,
|
---|
2259 | struct lock_struct *plock,
|
---|
2260 | bool blocking_lock)
|
---|
2261 | {
|
---|
2262 | SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
|
---|
2263 |
|
---|
2264 | /* Note: blr is not used in the default implementation. */
|
---|
2265 | return brl_lock_windows_default(br_lck, plock, blocking_lock);
|
---|
2266 | }
|
---|
2267 |
|
---|
2268 | static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
|
---|
2269 | struct messaging_context *msg_ctx,
|
---|
2270 | struct byte_range_lock *br_lck,
|
---|
2271 | const struct lock_struct *plock)
|
---|
2272 | {
|
---|
2273 | SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
|
---|
2274 |
|
---|
2275 | return brl_unlock_windows_default(msg_ctx, br_lck, plock);
|
---|
2276 | }
|
---|
2277 |
|
---|
2278 | static bool vfswrap_brl_cancel_windows(struct vfs_handle_struct *handle,
|
---|
2279 | struct byte_range_lock *br_lck,
|
---|
2280 | struct lock_struct *plock)
|
---|
2281 | {
|
---|
2282 | SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
|
---|
2283 |
|
---|
2284 | /* Note: blr is not used in the default implementation. */
|
---|
2285 | return brl_lock_cancel_default(br_lck, plock);
|
---|
2286 | }
|
---|
2287 |
|
---|
2288 | static bool vfswrap_strict_lock(struct vfs_handle_struct *handle,
|
---|
2289 | files_struct *fsp,
|
---|
2290 | struct lock_struct *plock)
|
---|
2291 | {
|
---|
2292 | SMB_ASSERT(plock->lock_type == READ_LOCK ||
|
---|
2293 | plock->lock_type == WRITE_LOCK);
|
---|
2294 |
|
---|
2295 | return strict_lock_default(fsp, plock);
|
---|
2296 | }
|
---|
2297 |
|
---|
2298 | static void vfswrap_strict_unlock(struct vfs_handle_struct *handle,
|
---|
2299 | files_struct *fsp,
|
---|
2300 | struct lock_struct *plock)
|
---|
2301 | {
|
---|
2302 | SMB_ASSERT(plock->lock_type == READ_LOCK ||
|
---|
2303 | plock->lock_type == WRITE_LOCK);
|
---|
2304 |
|
---|
2305 | strict_unlock_default(fsp, plock);
|
---|
2306 | }
|
---|
2307 |
|
---|
2308 | /* NT ACL operations. */
|
---|
2309 |
|
---|
2310 | static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
|
---|
2311 | files_struct *fsp,
|
---|
2312 | uint32_t security_info,
|
---|
2313 | TALLOC_CTX *mem_ctx,
|
---|
2314 | struct security_descriptor **ppdesc)
|
---|
2315 | {
|
---|
2316 | NTSTATUS result;
|
---|
2317 |
|
---|
2318 | START_PROFILE(fget_nt_acl);
|
---|
2319 | result = posix_fget_nt_acl(fsp, security_info,
|
---|
2320 | mem_ctx, ppdesc);
|
---|
2321 | END_PROFILE(fget_nt_acl);
|
---|
2322 | return result;
|
---|
2323 | }
|
---|
2324 |
|
---|
2325 | static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
|
---|
2326 | const char *name,
|
---|
2327 | uint32_t security_info,
|
---|
2328 | TALLOC_CTX *mem_ctx,
|
---|
2329 | struct security_descriptor **ppdesc)
|
---|
2330 | {
|
---|
2331 | NTSTATUS result;
|
---|
2332 |
|
---|
2333 | START_PROFILE(get_nt_acl);
|
---|
2334 | result = posix_get_nt_acl(handle->conn, name, security_info,
|
---|
2335 | mem_ctx, ppdesc);
|
---|
2336 | END_PROFILE(get_nt_acl);
|
---|
2337 | return result;
|
---|
2338 | }
|
---|
2339 |
|
---|
2340 | static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
|
---|
2341 | {
|
---|
2342 | NTSTATUS result;
|
---|
2343 |
|
---|
2344 | START_PROFILE(fset_nt_acl);
|
---|
2345 | result = set_nt_acl(fsp, security_info_sent, psd);
|
---|
2346 | END_PROFILE(fset_nt_acl);
|
---|
2347 | return result;
|
---|
2348 | }
|
---|
2349 |
|
---|
2350 | static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
|
---|
2351 | struct smb_filename *file,
|
---|
2352 | struct security_acl *sacl,
|
---|
2353 | uint32_t access_requested,
|
---|
2354 | uint32_t access_denied)
|
---|
2355 | {
|
---|
2356 | return NT_STATUS_OK; /* Nothing to do here ... */
|
---|
2357 | }
|
---|
2358 |
|
---|
2359 | static int vfswrap_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode)
|
---|
2360 | {
|
---|
2361 | #ifdef HAVE_NO_ACL
|
---|
2362 | errno = ENOSYS;
|
---|
2363 | return -1;
|
---|
2364 | #else
|
---|
2365 | int result;
|
---|
2366 |
|
---|
2367 | START_PROFILE(chmod_acl);
|
---|
2368 | result = chmod_acl(handle->conn, name, mode);
|
---|
2369 | END_PROFILE(chmod_acl);
|
---|
2370 | return result;
|
---|
2371 | #endif
|
---|
2372 | }
|
---|
2373 |
|
---|
2374 | static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
|
---|
2375 | {
|
---|
2376 | #ifdef HAVE_NO_ACL
|
---|
2377 | errno = ENOSYS;
|
---|
2378 | return -1;
|
---|
2379 | #else
|
---|
2380 | int result;
|
---|
2381 |
|
---|
2382 | START_PROFILE(fchmod_acl);
|
---|
2383 | result = fchmod_acl(fsp, mode);
|
---|
2384 | END_PROFILE(fchmod_acl);
|
---|
2385 | return result;
|
---|
2386 | #endif
|
---|
2387 | }
|
---|
2388 |
|
---|
2389 | static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle,
|
---|
2390 | const char *path_p,
|
---|
2391 | SMB_ACL_TYPE_T type,
|
---|
2392 | TALLOC_CTX *mem_ctx)
|
---|
2393 | {
|
---|
2394 | return sys_acl_get_file(handle, path_p, type, mem_ctx);
|
---|
2395 | }
|
---|
2396 |
|
---|
2397 | static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
|
---|
2398 | files_struct *fsp,
|
---|
2399 | TALLOC_CTX *mem_ctx)
|
---|
2400 | {
|
---|
2401 | return sys_acl_get_fd(handle, fsp, mem_ctx);
|
---|
2402 | }
|
---|
2403 |
|
---|
2404 | static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
|
---|
2405 | {
|
---|
2406 | return sys_acl_set_file(handle, name, acltype, theacl);
|
---|
2407 | }
|
---|
2408 |
|
---|
2409 | static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
|
---|
2410 | {
|
---|
2411 | return sys_acl_set_fd(handle, fsp, theacl);
|
---|
2412 | }
|
---|
2413 |
|
---|
2414 | static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
|
---|
2415 | {
|
---|
2416 | return sys_acl_delete_def_file(handle, path);
|
---|
2417 | }
|
---|
2418 |
|
---|
2419 | /****************************************************************
|
---|
2420 | Extended attribute operations.
|
---|
2421 | *****************************************************************/
|
---|
2422 |
|
---|
2423 | static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
|
---|
2424 | {
|
---|
2425 | return getxattr(path, name, value, size);
|
---|
2426 | }
|
---|
2427 |
|
---|
2428 | static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
|
---|
2429 | {
|
---|
2430 | return fgetxattr(fsp->fh->fd, name, value, size);
|
---|
2431 | }
|
---|
2432 |
|
---|
2433 | static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
|
---|
2434 | {
|
---|
2435 | return listxattr(path, list, size);
|
---|
2436 | }
|
---|
2437 |
|
---|
2438 | static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
|
---|
2439 | {
|
---|
2440 | return flistxattr(fsp->fh->fd, list, size);
|
---|
2441 | }
|
---|
2442 |
|
---|
2443 | static int vfswrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
|
---|
2444 | {
|
---|
2445 | return removexattr(path, name);
|
---|
2446 | }
|
---|
2447 |
|
---|
2448 | static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
|
---|
2449 | {
|
---|
2450 | return fremovexattr(fsp->fh->fd, name);
|
---|
2451 | }
|
---|
2452 |
|
---|
2453 | static int vfswrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
|
---|
2454 | {
|
---|
2455 | return setxattr(path, name, value, size, flags);
|
---|
2456 | }
|
---|
2457 |
|
---|
2458 | static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
|
---|
2459 | {
|
---|
2460 | return fsetxattr(fsp->fh->fd, name, value, size, flags);
|
---|
2461 | }
|
---|
2462 |
|
---|
2463 | static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
|
---|
2464 | {
|
---|
2465 | return false;
|
---|
2466 | }
|
---|
2467 |
|
---|
2468 | static bool vfswrap_is_offline(struct vfs_handle_struct *handle,
|
---|
2469 | const struct smb_filename *fname,
|
---|
2470 | SMB_STRUCT_STAT *sbuf)
|
---|
2471 | {
|
---|
2472 | NTSTATUS status;
|
---|
2473 | char *path;
|
---|
2474 | bool offline = false;
|
---|
2475 |
|
---|
2476 | if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
|
---|
2477 | return false;
|
---|
2478 | }
|
---|
2479 |
|
---|
2480 | if (!lp_dmapi_support(SNUM(handle->conn)) || !dmapi_have_session()) {
|
---|
2481 | #if defined(ENOTSUP)
|
---|
2482 | errno = ENOTSUP;
|
---|
2483 | #endif
|
---|
2484 | return false;
|
---|
2485 | }
|
---|
2486 |
|
---|
2487 | status = get_full_smb_filename(talloc_tos(), fname, &path);
|
---|
2488 | if (!NT_STATUS_IS_OK(status)) {
|
---|
2489 | errno = map_errno_from_nt_status(status);
|
---|
2490 | return false;
|
---|
2491 | }
|
---|
2492 |
|
---|
2493 | offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
|
---|
2494 |
|
---|
2495 | TALLOC_FREE(path);
|
---|
2496 |
|
---|
2497 | return offline;
|
---|
2498 | }
|
---|
2499 |
|
---|
2500 | static int vfswrap_set_offline(struct vfs_handle_struct *handle,
|
---|
2501 | const struct smb_filename *fname)
|
---|
2502 | {
|
---|
2503 | /* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */
|
---|
2504 | #if defined(ENOTSUP)
|
---|
2505 | errno = ENOTSUP;
|
---|
2506 | #endif
|
---|
2507 | return -1;
|
---|
2508 | }
|
---|
2509 |
|
---|
2510 | static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
|
---|
2511 | struct files_struct *fsp,
|
---|
2512 | TALLOC_CTX *mem_ctx,
|
---|
2513 | DATA_BLOB *cookie)
|
---|
2514 | {
|
---|
2515 | return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
|
---|
2516 | }
|
---|
2517 |
|
---|
2518 | static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
|
---|
2519 | struct files_struct *fsp,
|
---|
2520 | const DATA_BLOB old_cookie,
|
---|
2521 | TALLOC_CTX *mem_ctx,
|
---|
2522 | DATA_BLOB *new_cookie)
|
---|
2523 | {
|
---|
2524 | return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
|
---|
2525 | new_cookie);
|
---|
2526 | }
|
---|
2527 |
|
---|
2528 | static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
|
---|
2529 | struct smb_request *smb1req,
|
---|
2530 | struct smbXsrv_open *op,
|
---|
2531 | const DATA_BLOB old_cookie,
|
---|
2532 | TALLOC_CTX *mem_ctx,
|
---|
2533 | struct files_struct **fsp,
|
---|
2534 | DATA_BLOB *new_cookie)
|
---|
2535 | {
|
---|
2536 | return vfs_default_durable_reconnect(handle->conn, smb1req, op,
|
---|
2537 | old_cookie, mem_ctx,
|
---|
2538 | fsp, new_cookie);
|
---|
2539 | }
|
---|
2540 |
|
---|
2541 | static struct vfs_fn_pointers vfs_default_fns = {
|
---|
2542 | /* Disk operations */
|
---|
2543 |
|
---|
2544 | .connect_fn = vfswrap_connect,
|
---|
2545 | .disconnect_fn = vfswrap_disconnect,
|
---|
2546 | .disk_free_fn = vfswrap_disk_free,
|
---|
2547 | .get_quota_fn = vfswrap_get_quota,
|
---|
2548 | .set_quota_fn = vfswrap_set_quota,
|
---|
2549 | .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
|
---|
2550 | .statvfs_fn = vfswrap_statvfs,
|
---|
2551 | .fs_capabilities_fn = vfswrap_fs_capabilities,
|
---|
2552 | .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
|
---|
2553 | .snap_check_path_fn = vfswrap_snap_check_path,
|
---|
2554 | .snap_create_fn = vfswrap_snap_create,
|
---|
2555 | .snap_delete_fn = vfswrap_snap_delete,
|
---|
2556 |
|
---|
2557 | /* Directory operations */
|
---|
2558 |
|
---|
2559 | .opendir_fn = vfswrap_opendir,
|
---|
2560 | .fdopendir_fn = vfswrap_fdopendir,
|
---|
2561 | .readdir_fn = vfswrap_readdir,
|
---|
2562 | .readdir_attr_fn = vfswrap_readdir_attr,
|
---|
2563 | .seekdir_fn = vfswrap_seekdir,
|
---|
2564 | .telldir_fn = vfswrap_telldir,
|
---|
2565 | .rewind_dir_fn = vfswrap_rewinddir,
|
---|
2566 | .mkdir_fn = vfswrap_mkdir,
|
---|
2567 | .rmdir_fn = vfswrap_rmdir,
|
---|
2568 | .closedir_fn = vfswrap_closedir,
|
---|
2569 | .init_search_op_fn = vfswrap_init_search_op,
|
---|
2570 |
|
---|
2571 | /* File operations */
|
---|
2572 |
|
---|
2573 | .open_fn = vfswrap_open,
|
---|
2574 | .create_file_fn = vfswrap_create_file,
|
---|
2575 | .close_fn = vfswrap_close,
|
---|
2576 | .read_fn = vfswrap_read,
|
---|
2577 | .pread_fn = vfswrap_pread,
|
---|
2578 | .pread_send_fn = vfswrap_pread_send,
|
---|
2579 | .pread_recv_fn = vfswrap_asys_ssize_t_recv,
|
---|
2580 | .write_fn = vfswrap_write,
|
---|
2581 | .pwrite_fn = vfswrap_pwrite,
|
---|
2582 | .pwrite_send_fn = vfswrap_pwrite_send,
|
---|
2583 | .pwrite_recv_fn = vfswrap_asys_ssize_t_recv,
|
---|
2584 | .lseek_fn = vfswrap_lseek,
|
---|
2585 | .sendfile_fn = vfswrap_sendfile,
|
---|
2586 | .recvfile_fn = vfswrap_recvfile,
|
---|
2587 | .rename_fn = vfswrap_rename,
|
---|
2588 | .fsync_fn = vfswrap_fsync,
|
---|
2589 | .fsync_send_fn = vfswrap_fsync_send,
|
---|
2590 | .fsync_recv_fn = vfswrap_asys_int_recv,
|
---|
2591 | .stat_fn = vfswrap_stat,
|
---|
2592 | .fstat_fn = vfswrap_fstat,
|
---|
2593 | .lstat_fn = vfswrap_lstat,
|
---|
2594 | .get_alloc_size_fn = vfswrap_get_alloc_size,
|
---|
2595 | .unlink_fn = vfswrap_unlink,
|
---|
2596 | .chmod_fn = vfswrap_chmod,
|
---|
2597 | .fchmod_fn = vfswrap_fchmod,
|
---|
2598 | .chown_fn = vfswrap_chown,
|
---|
2599 | .fchown_fn = vfswrap_fchown,
|
---|
2600 | .lchown_fn = vfswrap_lchown,
|
---|
2601 | .chdir_fn = vfswrap_chdir,
|
---|
2602 | .getwd_fn = vfswrap_getwd,
|
---|
2603 | .ntimes_fn = vfswrap_ntimes,
|
---|
2604 | .ftruncate_fn = vfswrap_ftruncate,
|
---|
2605 | .fallocate_fn = vfswrap_fallocate,
|
---|
2606 | .lock_fn = vfswrap_lock,
|
---|
2607 | .kernel_flock_fn = vfswrap_kernel_flock,
|
---|
2608 | .linux_setlease_fn = vfswrap_linux_setlease,
|
---|
2609 | .getlock_fn = vfswrap_getlock,
|
---|
2610 | .symlink_fn = vfswrap_symlink,
|
---|
2611 | .readlink_fn = vfswrap_readlink,
|
---|
2612 | .link_fn = vfswrap_link,
|
---|
2613 | .mknod_fn = vfswrap_mknod,
|
---|
2614 | .realpath_fn = vfswrap_realpath,
|
---|
2615 | .chflags_fn = vfswrap_chflags,
|
---|
2616 | .file_id_create_fn = vfswrap_file_id_create,
|
---|
2617 | .streaminfo_fn = vfswrap_streaminfo,
|
---|
2618 | .get_real_filename_fn = vfswrap_get_real_filename,
|
---|
2619 | .connectpath_fn = vfswrap_connectpath,
|
---|
2620 | .brl_lock_windows_fn = vfswrap_brl_lock_windows,
|
---|
2621 | .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
|
---|
2622 | .brl_cancel_windows_fn = vfswrap_brl_cancel_windows,
|
---|
2623 | .strict_lock_fn = vfswrap_strict_lock,
|
---|
2624 | .strict_unlock_fn = vfswrap_strict_unlock,
|
---|
2625 | .translate_name_fn = vfswrap_translate_name,
|
---|
2626 | .fsctl_fn = vfswrap_fsctl,
|
---|
2627 | .copy_chunk_send_fn = vfswrap_copy_chunk_send,
|
---|
2628 | .copy_chunk_recv_fn = vfswrap_copy_chunk_recv,
|
---|
2629 | .get_compression_fn = vfswrap_get_compression,
|
---|
2630 | .set_compression_fn = vfswrap_set_compression,
|
---|
2631 |
|
---|
2632 | /* NT ACL operations. */
|
---|
2633 |
|
---|
2634 | .fget_nt_acl_fn = vfswrap_fget_nt_acl,
|
---|
2635 | .get_nt_acl_fn = vfswrap_get_nt_acl,
|
---|
2636 | .fset_nt_acl_fn = vfswrap_fset_nt_acl,
|
---|
2637 | .audit_file_fn = vfswrap_audit_file,
|
---|
2638 |
|
---|
2639 | /* POSIX ACL operations. */
|
---|
2640 |
|
---|
2641 | .chmod_acl_fn = vfswrap_chmod_acl,
|
---|
2642 | .fchmod_acl_fn = vfswrap_fchmod_acl,
|
---|
2643 |
|
---|
2644 | .sys_acl_get_file_fn = vfswrap_sys_acl_get_file,
|
---|
2645 | .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
|
---|
2646 | .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
|
---|
2647 | .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
|
---|
2648 | .sys_acl_set_file_fn = vfswrap_sys_acl_set_file,
|
---|
2649 | .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
|
---|
2650 | .sys_acl_delete_def_file_fn = vfswrap_sys_acl_delete_def_file,
|
---|
2651 |
|
---|
2652 | /* EA operations. */
|
---|
2653 | .getxattr_fn = vfswrap_getxattr,
|
---|
2654 | .fgetxattr_fn = vfswrap_fgetxattr,
|
---|
2655 | .listxattr_fn = vfswrap_listxattr,
|
---|
2656 | .flistxattr_fn = vfswrap_flistxattr,
|
---|
2657 | .removexattr_fn = vfswrap_removexattr,
|
---|
2658 | .fremovexattr_fn = vfswrap_fremovexattr,
|
---|
2659 | .setxattr_fn = vfswrap_setxattr,
|
---|
2660 | .fsetxattr_fn = vfswrap_fsetxattr,
|
---|
2661 |
|
---|
2662 | /* aio operations */
|
---|
2663 | .aio_force_fn = vfswrap_aio_force,
|
---|
2664 |
|
---|
2665 | /* offline operations */
|
---|
2666 | .is_offline_fn = vfswrap_is_offline,
|
---|
2667 | .set_offline_fn = vfswrap_set_offline,
|
---|
2668 |
|
---|
2669 | /* durable handle operations */
|
---|
2670 | .durable_cookie_fn = vfswrap_durable_cookie,
|
---|
2671 | .durable_disconnect_fn = vfswrap_durable_disconnect,
|
---|
2672 | .durable_reconnect_fn = vfswrap_durable_reconnect,
|
---|
2673 | };
|
---|
2674 |
|
---|
2675 | NTSTATUS vfs_default_init(void);
|
---|
2676 | NTSTATUS vfs_default_init(void)
|
---|
2677 | {
|
---|
2678 | return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
|
---|
2679 | DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);
|
---|
2680 | }
|
---|
2681 |
|
---|
2682 |
|
---|