1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 |
|
---|
4 | Wrap GlusterFS GFAPI calls in vfs functions.
|
---|
5 |
|
---|
6 | Copyright (c) 2013 Anand Avati <avati@redhat.com>
|
---|
7 |
|
---|
8 | This program is free software; you can redistribute it and/or modify
|
---|
9 | it under the terms of the GNU General Public License as published by
|
---|
10 | the Free Software Foundation; either version 3 of the License, or
|
---|
11 | (at your option) any later version.
|
---|
12 |
|
---|
13 | This program is distributed in the hope that it will be useful,
|
---|
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
16 | GNU General Public License for more details.
|
---|
17 |
|
---|
18 | You should have received a copy of the GNU General Public License
|
---|
19 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
20 | */
|
---|
21 |
|
---|
22 | /**
|
---|
23 | * @file vfs_glusterfs.c
|
---|
24 | * @author Anand Avati <avati@redhat.com>
|
---|
25 | * @date May 2013
|
---|
26 | * @brief Samba VFS module for glusterfs
|
---|
27 | *
|
---|
28 | * @todo
|
---|
29 | * - sendfile/recvfile support
|
---|
30 | *
|
---|
31 | * A Samba VFS module for GlusterFS, based on Gluster's libgfapi.
|
---|
32 | * This is a "bottom" vfs module (not something to be stacked on top of
|
---|
33 | * another module), and translates (most) calls to the closest actions
|
---|
34 | * available in libgfapi.
|
---|
35 | *
|
---|
36 | */
|
---|
37 |
|
---|
38 | #include "includes.h"
|
---|
39 | #include "smbd/smbd.h"
|
---|
40 | #include <stdio.h>
|
---|
41 | #include "api/glfs.h"
|
---|
42 | #include "lib/util/dlinklist.h"
|
---|
43 | #include "lib/util/tevent_unix.h"
|
---|
44 | #include "smbd/globals.h"
|
---|
45 | #include "lib/util/sys_rw.h"
|
---|
46 |
|
---|
47 | #define DEFAULT_VOLFILE_SERVER "localhost"
|
---|
48 |
|
---|
49 | static int read_fd = -1;
|
---|
50 | static int write_fd = -1;
|
---|
51 | static struct tevent_fd *aio_read_event = NULL;
|
---|
52 |
|
---|
53 | /**
|
---|
54 | * Helper to convert struct stat to struct stat_ex.
|
---|
55 | */
|
---|
56 | static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
|
---|
57 | {
|
---|
58 | ZERO_STRUCTP(dst);
|
---|
59 |
|
---|
60 | dst->st_ex_dev = src->st_dev;
|
---|
61 | dst->st_ex_ino = src->st_ino;
|
---|
62 | dst->st_ex_mode = src->st_mode;
|
---|
63 | dst->st_ex_nlink = src->st_nlink;
|
---|
64 | dst->st_ex_uid = src->st_uid;
|
---|
65 | dst->st_ex_gid = src->st_gid;
|
---|
66 | dst->st_ex_rdev = src->st_rdev;
|
---|
67 | dst->st_ex_size = src->st_size;
|
---|
68 | dst->st_ex_atime.tv_sec = src->st_atime;
|
---|
69 | dst->st_ex_mtime.tv_sec = src->st_mtime;
|
---|
70 | dst->st_ex_ctime.tv_sec = src->st_ctime;
|
---|
71 | dst->st_ex_btime.tv_sec = src->st_mtime;
|
---|
72 | dst->st_ex_blksize = src->st_blksize;
|
---|
73 | dst->st_ex_blocks = src->st_blocks;
|
---|
74 | #ifdef STAT_HAVE_NSEC
|
---|
75 | dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
|
---|
76 | dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
|
---|
77 | dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
|
---|
78 | dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
|
---|
79 | #endif
|
---|
80 | }
|
---|
81 |
|
---|
82 | /* pre-opened glfs_t */
|
---|
83 |
|
---|
84 | static struct glfs_preopened {
|
---|
85 | char *volume;
|
---|
86 | char *connectpath;
|
---|
87 | glfs_t *fs;
|
---|
88 | int ref;
|
---|
89 | struct glfs_preopened *next, *prev;
|
---|
90 | } *glfs_preopened;
|
---|
91 |
|
---|
92 |
|
---|
93 | static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
|
---|
94 | {
|
---|
95 | struct glfs_preopened *entry = NULL;
|
---|
96 |
|
---|
97 | entry = talloc_zero(NULL, struct glfs_preopened);
|
---|
98 | if (!entry) {
|
---|
99 | errno = ENOMEM;
|
---|
100 | return -1;
|
---|
101 | }
|
---|
102 |
|
---|
103 | entry->volume = talloc_strdup(entry, volume);
|
---|
104 | if (!entry->volume) {
|
---|
105 | talloc_free(entry);
|
---|
106 | errno = ENOMEM;
|
---|
107 | return -1;
|
---|
108 | }
|
---|
109 |
|
---|
110 | entry->connectpath = talloc_strdup(entry, connectpath);
|
---|
111 | if (entry->connectpath == NULL) {
|
---|
112 | talloc_free(entry);
|
---|
113 | errno = ENOMEM;
|
---|
114 | return -1;
|
---|
115 | }
|
---|
116 |
|
---|
117 | entry->fs = fs;
|
---|
118 | entry->ref = 1;
|
---|
119 |
|
---|
120 | DLIST_ADD(glfs_preopened, entry);
|
---|
121 |
|
---|
122 | return 0;
|
---|
123 | }
|
---|
124 |
|
---|
125 | static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
|
---|
126 | {
|
---|
127 | struct glfs_preopened *entry = NULL;
|
---|
128 |
|
---|
129 | for (entry = glfs_preopened; entry; entry = entry->next) {
|
---|
130 | if (strcmp(entry->volume, volume) == 0 &&
|
---|
131 | strcmp(entry->connectpath, connectpath) == 0)
|
---|
132 | {
|
---|
133 | entry->ref++;
|
---|
134 | return entry->fs;
|
---|
135 | }
|
---|
136 | }
|
---|
137 |
|
---|
138 | return NULL;
|
---|
139 | }
|
---|
140 |
|
---|
141 | static void glfs_clear_preopened(glfs_t *fs)
|
---|
142 | {
|
---|
143 | struct glfs_preopened *entry = NULL;
|
---|
144 |
|
---|
145 | for (entry = glfs_preopened; entry; entry = entry->next) {
|
---|
146 | if (entry->fs == fs) {
|
---|
147 | if (--entry->ref)
|
---|
148 | return;
|
---|
149 |
|
---|
150 | DLIST_REMOVE(glfs_preopened, entry);
|
---|
151 |
|
---|
152 | glfs_fini(entry->fs);
|
---|
153 | talloc_free(entry);
|
---|
154 | }
|
---|
155 | }
|
---|
156 | }
|
---|
157 |
|
---|
158 | /* Disk Operations */
|
---|
159 |
|
---|
160 | static int vfs_gluster_connect(struct vfs_handle_struct *handle,
|
---|
161 | const char *service,
|
---|
162 | const char *user)
|
---|
163 | {
|
---|
164 | const char *volfile_server;
|
---|
165 | const char *volume;
|
---|
166 | char *logfile;
|
---|
167 | int loglevel;
|
---|
168 | glfs_t *fs = NULL;
|
---|
169 | TALLOC_CTX *tmp_ctx;
|
---|
170 | int ret = 0;
|
---|
171 |
|
---|
172 | tmp_ctx = talloc_new(NULL);
|
---|
173 | if (tmp_ctx == NULL) {
|
---|
174 | ret = -1;
|
---|
175 | goto done;
|
---|
176 | }
|
---|
177 | logfile = lp_parm_talloc_string(tmp_ctx, SNUM(handle->conn), "glusterfs",
|
---|
178 | "logfile", NULL);
|
---|
179 |
|
---|
180 | loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
|
---|
181 |
|
---|
182 | volfile_server = lp_parm_const_string(SNUM(handle->conn), "glusterfs",
|
---|
183 | "volfile_server", NULL);
|
---|
184 | if (volfile_server == NULL) {
|
---|
185 | volfile_server = DEFAULT_VOLFILE_SERVER;
|
---|
186 | }
|
---|
187 |
|
---|
188 | volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
|
---|
189 | NULL);
|
---|
190 | if (volume == NULL) {
|
---|
191 | volume = service;
|
---|
192 | }
|
---|
193 |
|
---|
194 | fs = glfs_find_preopened(volume, handle->conn->connectpath);
|
---|
195 | if (fs) {
|
---|
196 | goto done;
|
---|
197 | }
|
---|
198 |
|
---|
199 | fs = glfs_new(volume);
|
---|
200 | if (fs == NULL) {
|
---|
201 | ret = -1;
|
---|
202 | goto done;
|
---|
203 | }
|
---|
204 |
|
---|
205 | ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 0);
|
---|
206 | if (ret < 0) {
|
---|
207 | DEBUG(0, ("Failed to set volfile_server %s\n", volfile_server));
|
---|
208 | goto done;
|
---|
209 | }
|
---|
210 |
|
---|
211 | ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
|
---|
212 | "true");
|
---|
213 | if (ret < 0) {
|
---|
214 | DEBUG(0, ("%s: Failed to set xlator options\n", volume));
|
---|
215 | goto done;
|
---|
216 | }
|
---|
217 |
|
---|
218 |
|
---|
219 | ret = glfs_set_xlator_option(fs, "*-snapview-client",
|
---|
220 | "snapdir-entry-path",
|
---|
221 | handle->conn->connectpath);
|
---|
222 | if (ret < 0) {
|
---|
223 | DEBUG(0, ("%s: Failed to set xlator option:"
|
---|
224 | " snapdir-entry-path\n", volume));
|
---|
225 | goto done;
|
---|
226 | }
|
---|
227 |
|
---|
228 | ret = glfs_set_logging(fs, logfile, loglevel);
|
---|
229 | if (ret < 0) {
|
---|
230 | DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
|
---|
231 | volume, logfile, loglevel));
|
---|
232 | goto done;
|
---|
233 | }
|
---|
234 |
|
---|
235 | ret = glfs_init(fs);
|
---|
236 | if (ret < 0) {
|
---|
237 | DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
|
---|
238 | volume, strerror(errno)));
|
---|
239 | goto done;
|
---|
240 | }
|
---|
241 |
|
---|
242 | ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
|
---|
243 | if (ret < 0) {
|
---|
244 | DEBUG(0, ("%s: Failed to register volume (%s)\n",
|
---|
245 | volume, strerror(errno)));
|
---|
246 | goto done;
|
---|
247 | }
|
---|
248 | done:
|
---|
249 | talloc_free(tmp_ctx);
|
---|
250 | if (ret < 0) {
|
---|
251 | if (fs)
|
---|
252 | glfs_fini(fs);
|
---|
253 | return -1;
|
---|
254 | } else {
|
---|
255 | DEBUG(0, ("%s: Initialized volume from server %s\n",
|
---|
256 | volume, volfile_server));
|
---|
257 | handle->data = fs;
|
---|
258 | return 0;
|
---|
259 | }
|
---|
260 | }
|
---|
261 |
|
---|
262 | static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
|
---|
263 | {
|
---|
264 | glfs_t *fs = NULL;
|
---|
265 |
|
---|
266 | fs = handle->data;
|
---|
267 |
|
---|
268 | glfs_clear_preopened(fs);
|
---|
269 | }
|
---|
270 |
|
---|
271 | static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
|
---|
272 | const char *path, uint64_t *bsize_p,
|
---|
273 | uint64_t *dfree_p, uint64_t *dsize_p)
|
---|
274 | {
|
---|
275 | struct statvfs statvfs = { 0, };
|
---|
276 | int ret;
|
---|
277 |
|
---|
278 | ret = glfs_statvfs(handle->data, path, &statvfs);
|
---|
279 | if (ret < 0) {
|
---|
280 | return -1;
|
---|
281 | }
|
---|
282 |
|
---|
283 | if (bsize_p != NULL) {
|
---|
284 | *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
|
---|
285 | }
|
---|
286 | if (dfree_p != NULL) {
|
---|
287 | *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
|
---|
288 | }
|
---|
289 | if (dsize_p != NULL) {
|
---|
290 | *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
|
---|
291 | }
|
---|
292 |
|
---|
293 | return (uint64_t)statvfs.f_bavail;
|
---|
294 | }
|
---|
295 |
|
---|
296 | static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
|
---|
297 | const char *path,
|
---|
298 | enum SMB_QUOTA_TYPE qtype, unid_t id,
|
---|
299 | SMB_DISK_QUOTA *qt)
|
---|
300 | {
|
---|
301 | errno = ENOSYS;
|
---|
302 | return -1;
|
---|
303 | }
|
---|
304 |
|
---|
305 | static int
|
---|
306 | vfs_gluster_set_quota(struct vfs_handle_struct *handle,
|
---|
307 | enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
|
---|
308 | {
|
---|
309 | errno = ENOSYS;
|
---|
310 | return -1;
|
---|
311 | }
|
---|
312 |
|
---|
313 | static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
|
---|
314 | const char *path,
|
---|
315 | struct vfs_statvfs_struct *vfs_statvfs)
|
---|
316 | {
|
---|
317 | struct statvfs statvfs = { 0, };
|
---|
318 | int ret;
|
---|
319 |
|
---|
320 | ret = glfs_statvfs(handle->data, path, &statvfs);
|
---|
321 | if (ret < 0) {
|
---|
322 | DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
|
---|
323 | path, strerror(errno)));
|
---|
324 | return -1;
|
---|
325 | }
|
---|
326 |
|
---|
327 | ZERO_STRUCTP(vfs_statvfs);
|
---|
328 |
|
---|
329 | vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
|
---|
330 | vfs_statvfs->BlockSize = statvfs.f_bsize;
|
---|
331 | vfs_statvfs->TotalBlocks = statvfs.f_blocks;
|
---|
332 | vfs_statvfs->BlocksAvail = statvfs.f_bfree;
|
---|
333 | vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
|
---|
334 | vfs_statvfs->TotalFileNodes = statvfs.f_files;
|
---|
335 | vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
|
---|
336 | vfs_statvfs->FsIdentifier = statvfs.f_fsid;
|
---|
337 | vfs_statvfs->FsCapabilities =
|
---|
338 | FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
|
---|
339 |
|
---|
340 | return ret;
|
---|
341 | }
|
---|
342 |
|
---|
343 | static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
|
---|
344 | enum timestamp_set_resolution *p_ts_res)
|
---|
345 | {
|
---|
346 | uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
|
---|
347 |
|
---|
348 | #ifdef STAT_HAVE_NSEC
|
---|
349 | *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
|
---|
350 | #endif
|
---|
351 |
|
---|
352 | return caps;
|
---|
353 | }
|
---|
354 |
|
---|
355 | static DIR *vfs_gluster_opendir(struct vfs_handle_struct *handle,
|
---|
356 | const char *path, const char *mask,
|
---|
357 | uint32_t attributes)
|
---|
358 | {
|
---|
359 | glfs_fd_t *fd;
|
---|
360 |
|
---|
361 | fd = glfs_opendir(handle->data, path);
|
---|
362 | if (fd == NULL) {
|
---|
363 | DEBUG(0, ("glfs_opendir(%s) failed: %s\n",
|
---|
364 | path, strerror(errno)));
|
---|
365 | }
|
---|
366 |
|
---|
367 | return (DIR *) fd;
|
---|
368 | }
|
---|
369 |
|
---|
370 | static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
|
---|
371 | files_struct *fsp, const char *mask,
|
---|
372 | uint32_t attributes)
|
---|
373 | {
|
---|
374 | return (DIR *) *(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
|
---|
375 | }
|
---|
376 |
|
---|
377 | static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
|
---|
378 | {
|
---|
379 | return glfs_closedir((void *)dirp);
|
---|
380 | }
|
---|
381 |
|
---|
382 | static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
|
---|
383 | DIR *dirp, SMB_STRUCT_STAT *sbuf)
|
---|
384 | {
|
---|
385 | static char direntbuf[512];
|
---|
386 | int ret;
|
---|
387 | struct stat stat;
|
---|
388 | struct dirent *dirent = 0;
|
---|
389 |
|
---|
390 | if (sbuf != NULL) {
|
---|
391 | ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
|
---|
392 | &dirent);
|
---|
393 | } else {
|
---|
394 | ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
|
---|
395 | }
|
---|
396 |
|
---|
397 | if ((ret < 0) || (dirent == NULL)) {
|
---|
398 | return NULL;
|
---|
399 | }
|
---|
400 |
|
---|
401 | if (sbuf != NULL) {
|
---|
402 | smb_stat_ex_from_stat(sbuf, &stat);
|
---|
403 | }
|
---|
404 |
|
---|
405 | return dirent;
|
---|
406 | }
|
---|
407 |
|
---|
408 | static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
|
---|
409 | {
|
---|
410 | return glfs_telldir((void *)dirp);
|
---|
411 | }
|
---|
412 |
|
---|
413 | static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
|
---|
414 | long offset)
|
---|
415 | {
|
---|
416 | glfs_seekdir((void *)dirp, offset);
|
---|
417 | }
|
---|
418 |
|
---|
419 | static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
|
---|
420 | {
|
---|
421 | glfs_seekdir((void *)dirp, 0);
|
---|
422 | }
|
---|
423 |
|
---|
424 | static void vfs_gluster_init_search_op(struct vfs_handle_struct *handle,
|
---|
425 | DIR *dirp)
|
---|
426 | {
|
---|
427 | return;
|
---|
428 | }
|
---|
429 |
|
---|
430 | static int vfs_gluster_mkdir(struct vfs_handle_struct *handle, const char *path,
|
---|
431 | mode_t mode)
|
---|
432 | {
|
---|
433 | return glfs_mkdir(handle->data, path, mode);
|
---|
434 | }
|
---|
435 |
|
---|
436 | static int vfs_gluster_rmdir(struct vfs_handle_struct *handle, const char *path)
|
---|
437 | {
|
---|
438 | return glfs_rmdir(handle->data, path);
|
---|
439 | }
|
---|
440 |
|
---|
441 | static int vfs_gluster_open(struct vfs_handle_struct *handle,
|
---|
442 | struct smb_filename *smb_fname, files_struct *fsp,
|
---|
443 | int flags, mode_t mode)
|
---|
444 | {
|
---|
445 | glfs_fd_t *glfd;
|
---|
446 | glfs_fd_t **p_tmp;
|
---|
447 |
|
---|
448 | if (flags & O_DIRECTORY) {
|
---|
449 | glfd = glfs_opendir(handle->data, smb_fname->base_name);
|
---|
450 | } else if (flags & O_CREAT) {
|
---|
451 | glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
|
---|
452 | mode);
|
---|
453 | } else {
|
---|
454 | glfd = glfs_open(handle->data, smb_fname->base_name, flags);
|
---|
455 | }
|
---|
456 |
|
---|
457 | if (glfd == NULL) {
|
---|
458 | return -1;
|
---|
459 | }
|
---|
460 | p_tmp = (glfs_fd_t **)VFS_ADD_FSP_EXTENSION(handle, fsp,
|
---|
461 | glfs_fd_t *, NULL);
|
---|
462 | *p_tmp = glfd;
|
---|
463 | /* An arbitrary value for error reporting, so you know its us. */
|
---|
464 | return 13371337;
|
---|
465 | }
|
---|
466 |
|
---|
467 | static int vfs_gluster_close(struct vfs_handle_struct *handle,
|
---|
468 | files_struct *fsp)
|
---|
469 | {
|
---|
470 | glfs_fd_t *glfd;
|
---|
471 | glfd = *(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
|
---|
472 | VFS_REMOVE_FSP_EXTENSION(handle, fsp);
|
---|
473 | return glfs_close(glfd);
|
---|
474 | }
|
---|
475 |
|
---|
476 | static ssize_t vfs_gluster_read(struct vfs_handle_struct *handle,
|
---|
477 | files_struct *fsp, void *data, size_t n)
|
---|
478 | {
|
---|
479 | return glfs_read(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, 0);
|
---|
480 | }
|
---|
481 |
|
---|
482 | static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
|
---|
483 | files_struct *fsp, void *data, size_t n,
|
---|
484 | off_t offset)
|
---|
485 | {
|
---|
486 | return glfs_pread(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
|
---|
487 | }
|
---|
488 |
|
---|
489 | struct glusterfs_aio_state;
|
---|
490 |
|
---|
491 | struct glusterfs_aio_wrapper {
|
---|
492 | struct glusterfs_aio_state *state;
|
---|
493 | };
|
---|
494 |
|
---|
495 | struct glusterfs_aio_state {
|
---|
496 | ssize_t ret;
|
---|
497 | int err;
|
---|
498 | struct tevent_req *req;
|
---|
499 | bool cancelled;
|
---|
500 | };
|
---|
501 |
|
---|
502 | static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap)
|
---|
503 | {
|
---|
504 | if (wrap->state != NULL) {
|
---|
505 | wrap->state->cancelled = true;
|
---|
506 | }
|
---|
507 |
|
---|
508 | return 0;
|
---|
509 | }
|
---|
510 |
|
---|
511 | /*
|
---|
512 | * This function is the callback that will be called on glusterfs
|
---|
513 | * threads once the async IO submitted is complete. To notify
|
---|
514 | * Samba of the completion we use a pipe based queue.
|
---|
515 | */
|
---|
516 | static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
|
---|
517 | {
|
---|
518 | struct glusterfs_aio_state *state = NULL;
|
---|
519 | int sts = 0;
|
---|
520 |
|
---|
521 | state = (struct glusterfs_aio_state *)data;
|
---|
522 |
|
---|
523 | if (ret < 0) {
|
---|
524 | state->ret = -1;
|
---|
525 | state->err = errno;
|
---|
526 | } else {
|
---|
527 | state->ret = ret;
|
---|
528 | state->err = 0;
|
---|
529 | }
|
---|
530 |
|
---|
531 | /*
|
---|
532 | * Write the state pointer to glusterfs_aio_state to the
|
---|
533 | * pipe, so we can call tevent_req_done() from the main thread,
|
---|
534 | * because tevent_req_done() is not designed to be executed in
|
---|
535 | * the multithread environment, so tevent_req_done() must be
|
---|
536 | * executed from the smbd main thread.
|
---|
537 | *
|
---|
538 | * write(2) on pipes with sizes under _POSIX_PIPE_BUF
|
---|
539 | * in size is atomic, without this, the use op pipes in this
|
---|
540 | * code would not work.
|
---|
541 | *
|
---|
542 | * sys_write is a thin enough wrapper around write(2)
|
---|
543 | * that we can trust it here.
|
---|
544 | */
|
---|
545 |
|
---|
546 | sts = sys_write(write_fd, &state, sizeof(struct glusterfs_aio_state *));
|
---|
547 | if (sts < 0) {
|
---|
548 | DEBUG(0,("\nWrite to pipe failed (%s)", strerror(errno)));
|
---|
549 | }
|
---|
550 |
|
---|
551 | return;
|
---|
552 | }
|
---|
553 |
|
---|
554 | /*
|
---|
555 | * Read each req off the pipe and process it.
|
---|
556 | */
|
---|
557 | static void aio_tevent_fd_done(struct tevent_context *event_ctx,
|
---|
558 | struct tevent_fd *fde,
|
---|
559 | uint16_t flags, void *data)
|
---|
560 | {
|
---|
561 | struct tevent_req *req = NULL;
|
---|
562 | struct glusterfs_aio_state *state = NULL;
|
---|
563 | int sts = 0;
|
---|
564 |
|
---|
565 | /*
|
---|
566 | * read(2) on pipes is atomic if the needed data is available
|
---|
567 | * in the pipe, per SUS and POSIX. Because we always write
|
---|
568 | * to the pipe in sizeof(struct tevent_req *) chunks, we can
|
---|
569 | * always read in those chunks, atomically.
|
---|
570 | *
|
---|
571 | * sys_read is a thin enough wrapper around read(2) that we
|
---|
572 | * can trust it here.
|
---|
573 | */
|
---|
574 |
|
---|
575 | sts = sys_read(read_fd, &state, sizeof(struct glusterfs_aio_state *));
|
---|
576 |
|
---|
577 | if (sts < 0) {
|
---|
578 | DEBUG(0,("\nRead from pipe failed (%s)", strerror(errno)));
|
---|
579 | }
|
---|
580 |
|
---|
581 | /* if we've cancelled the op, there is no req, so just clean up. */
|
---|
582 | if (state->cancelled == true) {
|
---|
583 | TALLOC_FREE(state);
|
---|
584 | return;
|
---|
585 | }
|
---|
586 |
|
---|
587 | req = state->req;
|
---|
588 |
|
---|
589 | if (req) {
|
---|
590 | tevent_req_done(req);
|
---|
591 | }
|
---|
592 | return;
|
---|
593 | }
|
---|
594 |
|
---|
595 | static bool init_gluster_aio(struct vfs_handle_struct *handle)
|
---|
596 | {
|
---|
597 | int fds[2];
|
---|
598 | int ret = -1;
|
---|
599 |
|
---|
600 | if (read_fd != -1) {
|
---|
601 | /*
|
---|
602 | * Already initialized.
|
---|
603 | */
|
---|
604 | return true;
|
---|
605 | }
|
---|
606 |
|
---|
607 | ret = pipe(fds);
|
---|
608 | if (ret == -1) {
|
---|
609 | goto fail;
|
---|
610 | }
|
---|
611 |
|
---|
612 | read_fd = fds[0];
|
---|
613 | write_fd = fds[1];
|
---|
614 |
|
---|
615 | aio_read_event = tevent_add_fd(handle->conn->sconn->ev_ctx,
|
---|
616 | NULL,
|
---|
617 | read_fd,
|
---|
618 | TEVENT_FD_READ,
|
---|
619 | aio_tevent_fd_done,
|
---|
620 | NULL);
|
---|
621 | if (aio_read_event == NULL) {
|
---|
622 | goto fail;
|
---|
623 | }
|
---|
624 |
|
---|
625 | return true;
|
---|
626 | fail:
|
---|
627 | TALLOC_FREE(aio_read_event);
|
---|
628 | if (read_fd != -1) {
|
---|
629 | close(read_fd);
|
---|
630 | close(write_fd);
|
---|
631 | read_fd = -1;
|
---|
632 | write_fd = -1;
|
---|
633 | }
|
---|
634 | return false;
|
---|
635 | }
|
---|
636 |
|
---|
637 | static struct glusterfs_aio_state *aio_state_create(TALLOC_CTX *mem_ctx)
|
---|
638 | {
|
---|
639 | struct tevent_req *req = NULL;
|
---|
640 | struct glusterfs_aio_state *state = NULL;
|
---|
641 | struct glusterfs_aio_wrapper *wrapper = NULL;
|
---|
642 |
|
---|
643 | req = tevent_req_create(mem_ctx, &wrapper, struct glusterfs_aio_wrapper);
|
---|
644 |
|
---|
645 | if (req == NULL) {
|
---|
646 | return NULL;
|
---|
647 | }
|
---|
648 |
|
---|
649 | state = talloc(NULL, struct glusterfs_aio_state);
|
---|
650 |
|
---|
651 | if (state == NULL) {
|
---|
652 | TALLOC_FREE(req);
|
---|
653 | return NULL;
|
---|
654 | }
|
---|
655 |
|
---|
656 | talloc_set_destructor(wrapper, aio_wrapper_destructor);
|
---|
657 | state->cancelled = false;
|
---|
658 | state->ret = 0;
|
---|
659 | state->err = 0;
|
---|
660 | state->req = req;
|
---|
661 |
|
---|
662 | wrapper->state = state;
|
---|
663 |
|
---|
664 | return state;
|
---|
665 | }
|
---|
666 |
|
---|
667 | static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
|
---|
668 | *handle, TALLOC_CTX *mem_ctx,
|
---|
669 | struct tevent_context *ev,
|
---|
670 | files_struct *fsp,
|
---|
671 | void *data, size_t n,
|
---|
672 | off_t offset)
|
---|
673 | {
|
---|
674 | struct glusterfs_aio_state *state = NULL;
|
---|
675 | struct tevent_req *req = NULL;
|
---|
676 | int ret = 0;
|
---|
677 |
|
---|
678 | state = aio_state_create(mem_ctx);
|
---|
679 |
|
---|
680 | if (state == NULL) {
|
---|
681 | return NULL;
|
---|
682 | }
|
---|
683 |
|
---|
684 | req = state->req;
|
---|
685 |
|
---|
686 | if (!init_gluster_aio(handle)) {
|
---|
687 | tevent_req_error(req, EIO);
|
---|
688 | return tevent_req_post(req, ev);
|
---|
689 | }
|
---|
690 |
|
---|
691 | ret = glfs_pread_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
|
---|
692 | fsp), data, n, offset, 0, aio_glusterfs_done,
|
---|
693 | state);
|
---|
694 | if (ret < 0) {
|
---|
695 | tevent_req_error(req, -ret);
|
---|
696 | return tevent_req_post(req, ev);
|
---|
697 | }
|
---|
698 |
|
---|
699 | return req;
|
---|
700 | }
|
---|
701 |
|
---|
702 | static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
|
---|
703 | *handle, TALLOC_CTX *mem_ctx,
|
---|
704 | struct tevent_context *ev,
|
---|
705 | files_struct *fsp,
|
---|
706 | const void *data, size_t n,
|
---|
707 | off_t offset)
|
---|
708 | {
|
---|
709 | struct glusterfs_aio_state *state = NULL;
|
---|
710 | struct tevent_req *req = NULL;
|
---|
711 | int ret = 0;
|
---|
712 |
|
---|
713 | state = aio_state_create(mem_ctx);
|
---|
714 |
|
---|
715 | if (state == NULL) {
|
---|
716 | return NULL;
|
---|
717 | }
|
---|
718 |
|
---|
719 | req = state->req;
|
---|
720 |
|
---|
721 | if (!init_gluster_aio(handle)) {
|
---|
722 | tevent_req_error(req, EIO);
|
---|
723 | return tevent_req_post(req, ev);
|
---|
724 | }
|
---|
725 |
|
---|
726 | ret = glfs_pwrite_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
|
---|
727 | fsp), data, n, offset, 0, aio_glusterfs_done,
|
---|
728 | state);
|
---|
729 | if (ret < 0) {
|
---|
730 | tevent_req_error(req, -ret);
|
---|
731 | return tevent_req_post(req, ev);
|
---|
732 | }
|
---|
733 |
|
---|
734 | return req;
|
---|
735 | }
|
---|
736 |
|
---|
737 | static ssize_t vfs_gluster_recv(struct tevent_req *req, int *err)
|
---|
738 | {
|
---|
739 | struct glusterfs_aio_wrapper *wrapper = NULL;
|
---|
740 | int ret = 0;
|
---|
741 |
|
---|
742 | wrapper = tevent_req_data(req, struct glusterfs_aio_wrapper);
|
---|
743 |
|
---|
744 | if (wrapper == NULL) {
|
---|
745 | return -1;
|
---|
746 | }
|
---|
747 |
|
---|
748 | if (wrapper->state == NULL) {
|
---|
749 | return -1;
|
---|
750 | }
|
---|
751 |
|
---|
752 | if (tevent_req_is_unix_error(req, err)) {
|
---|
753 | return -1;
|
---|
754 | }
|
---|
755 | if (wrapper->state->ret == -1) {
|
---|
756 | *err = wrapper->state->err;
|
---|
757 | }
|
---|
758 |
|
---|
759 | ret = wrapper->state->ret;
|
---|
760 |
|
---|
761 | /* Clean up the state, it is in a NULL context. */
|
---|
762 |
|
---|
763 | TALLOC_FREE(wrapper->state);
|
---|
764 |
|
---|
765 | return ret;
|
---|
766 | }
|
---|
767 |
|
---|
768 | static ssize_t vfs_gluster_write(struct vfs_handle_struct *handle,
|
---|
769 | files_struct *fsp, const void *data, size_t n)
|
---|
770 | {
|
---|
771 | return glfs_write(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, 0);
|
---|
772 | }
|
---|
773 |
|
---|
774 | static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
|
---|
775 | files_struct *fsp, const void *data,
|
---|
776 | size_t n, off_t offset)
|
---|
777 | {
|
---|
778 | return glfs_pwrite(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
|
---|
779 | }
|
---|
780 |
|
---|
781 | static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
|
---|
782 | files_struct *fsp, off_t offset, int whence)
|
---|
783 | {
|
---|
784 | return glfs_lseek(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), offset, whence);
|
---|
785 | }
|
---|
786 |
|
---|
787 | static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
|
---|
788 | files_struct *fromfsp,
|
---|
789 | const DATA_BLOB *hdr,
|
---|
790 | off_t offset, size_t n)
|
---|
791 | {
|
---|
792 | errno = ENOTSUP;
|
---|
793 | return -1;
|
---|
794 | }
|
---|
795 |
|
---|
796 | static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
|
---|
797 | int fromfd, files_struct *tofsp,
|
---|
798 | off_t offset, size_t n)
|
---|
799 | {
|
---|
800 | errno = ENOTSUP;
|
---|
801 | return -1;
|
---|
802 | }
|
---|
803 |
|
---|
804 | static int vfs_gluster_rename(struct vfs_handle_struct *handle,
|
---|
805 | const struct smb_filename *smb_fname_src,
|
---|
806 | const struct smb_filename *smb_fname_dst)
|
---|
807 | {
|
---|
808 | return glfs_rename(handle->data, smb_fname_src->base_name,
|
---|
809 | smb_fname_dst->base_name);
|
---|
810 | }
|
---|
811 |
|
---|
812 | static int vfs_gluster_fsync(struct vfs_handle_struct *handle,
|
---|
813 | files_struct *fsp)
|
---|
814 | {
|
---|
815 | return glfs_fsync(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp));
|
---|
816 | }
|
---|
817 |
|
---|
818 | static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
|
---|
819 | *handle, TALLOC_CTX *mem_ctx,
|
---|
820 | struct tevent_context *ev,
|
---|
821 | files_struct *fsp)
|
---|
822 | {
|
---|
823 | struct tevent_req *req = NULL;
|
---|
824 | struct glusterfs_aio_state *state = NULL;
|
---|
825 | int ret = 0;
|
---|
826 |
|
---|
827 | state = aio_state_create(mem_ctx);
|
---|
828 |
|
---|
829 | if (state == NULL) {
|
---|
830 | return NULL;
|
---|
831 | }
|
---|
832 |
|
---|
833 | req = state->req;
|
---|
834 |
|
---|
835 | if (!init_gluster_aio(handle)) {
|
---|
836 | tevent_req_error(req, EIO);
|
---|
837 | return tevent_req_post(req, ev);
|
---|
838 | }
|
---|
839 | ret = glfs_fsync_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
|
---|
840 | fsp), aio_glusterfs_done, req);
|
---|
841 | if (ret < 0) {
|
---|
842 | tevent_req_error(req, -ret);
|
---|
843 | return tevent_req_post(req, ev);
|
---|
844 | }
|
---|
845 | return req;
|
---|
846 | }
|
---|
847 |
|
---|
848 | static int vfs_gluster_fsync_recv(struct tevent_req *req, int *err)
|
---|
849 | {
|
---|
850 | /*
|
---|
851 | * Use implicit conversion ssize_t->int
|
---|
852 | */
|
---|
853 | return vfs_gluster_recv(req, err);
|
---|
854 | }
|
---|
855 |
|
---|
856 | static int vfs_gluster_stat(struct vfs_handle_struct *handle,
|
---|
857 | struct smb_filename *smb_fname)
|
---|
858 | {
|
---|
859 | struct stat st;
|
---|
860 | int ret;
|
---|
861 |
|
---|
862 | ret = glfs_stat(handle->data, smb_fname->base_name, &st);
|
---|
863 | if (ret == 0) {
|
---|
864 | smb_stat_ex_from_stat(&smb_fname->st, &st);
|
---|
865 | }
|
---|
866 | if (ret < 0 && errno != ENOENT) {
|
---|
867 | DEBUG(0, ("glfs_stat(%s) failed: %s\n",
|
---|
868 | smb_fname->base_name, strerror(errno)));
|
---|
869 | }
|
---|
870 | return ret;
|
---|
871 | }
|
---|
872 |
|
---|
873 | static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
|
---|
874 | files_struct *fsp, SMB_STRUCT_STAT *sbuf)
|
---|
875 | {
|
---|
876 | struct stat st;
|
---|
877 | int ret;
|
---|
878 |
|
---|
879 | ret = glfs_fstat(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), &st);
|
---|
880 | if (ret == 0) {
|
---|
881 | smb_stat_ex_from_stat(sbuf, &st);
|
---|
882 | }
|
---|
883 | if (ret < 0) {
|
---|
884 | DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
|
---|
885 | fsp->fh->fd, strerror(errno)));
|
---|
886 | }
|
---|
887 | return ret;
|
---|
888 | }
|
---|
889 |
|
---|
890 | static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
|
---|
891 | struct smb_filename *smb_fname)
|
---|
892 | {
|
---|
893 | struct stat st;
|
---|
894 | int ret;
|
---|
895 |
|
---|
896 | ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
|
---|
897 | if (ret == 0) {
|
---|
898 | smb_stat_ex_from_stat(&smb_fname->st, &st);
|
---|
899 | }
|
---|
900 | if (ret < 0 && errno != ENOENT) {
|
---|
901 | DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
|
---|
902 | smb_fname->base_name, strerror(errno)));
|
---|
903 | }
|
---|
904 | return ret;
|
---|
905 | }
|
---|
906 |
|
---|
907 | static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
|
---|
908 | files_struct *fsp,
|
---|
909 | const SMB_STRUCT_STAT *sbuf)
|
---|
910 | {
|
---|
911 | return sbuf->st_ex_blocks * 512;
|
---|
912 | }
|
---|
913 |
|
---|
914 | static int vfs_gluster_unlink(struct vfs_handle_struct *handle,
|
---|
915 | const struct smb_filename *smb_fname)
|
---|
916 | {
|
---|
917 | return glfs_unlink(handle->data, smb_fname->base_name);
|
---|
918 | }
|
---|
919 |
|
---|
920 | static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
|
---|
921 | const char *path, mode_t mode)
|
---|
922 | {
|
---|
923 | return glfs_chmod(handle->data, path, mode);
|
---|
924 | }
|
---|
925 |
|
---|
926 | static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
|
---|
927 | files_struct *fsp, mode_t mode)
|
---|
928 | {
|
---|
929 | return glfs_fchmod(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), mode);
|
---|
930 | }
|
---|
931 |
|
---|
932 | static int vfs_gluster_chown(struct vfs_handle_struct *handle,
|
---|
933 | const char *path, uid_t uid, gid_t gid)
|
---|
934 | {
|
---|
935 | return glfs_chown(handle->data, path, uid, gid);
|
---|
936 | }
|
---|
937 |
|
---|
938 | static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
|
---|
939 | files_struct *fsp, uid_t uid, gid_t gid)
|
---|
940 | {
|
---|
941 | return glfs_fchown(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), uid, gid);
|
---|
942 | }
|
---|
943 |
|
---|
944 | static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
|
---|
945 | const char *path, uid_t uid, gid_t gid)
|
---|
946 | {
|
---|
947 | return glfs_lchown(handle->data, path, uid, gid);
|
---|
948 | }
|
---|
949 |
|
---|
950 | static int vfs_gluster_chdir(struct vfs_handle_struct *handle, const char *path)
|
---|
951 | {
|
---|
952 | return glfs_chdir(handle->data, path);
|
---|
953 | }
|
---|
954 |
|
---|
955 | static char *vfs_gluster_getwd(struct vfs_handle_struct *handle)
|
---|
956 | {
|
---|
957 | char *cwd;
|
---|
958 | char *ret;
|
---|
959 |
|
---|
960 | cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
|
---|
961 | if (cwd == NULL) {
|
---|
962 | return NULL;
|
---|
963 | }
|
---|
964 |
|
---|
965 | ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
|
---|
966 | if (ret == 0) {
|
---|
967 | free(cwd);
|
---|
968 | }
|
---|
969 | return ret;
|
---|
970 | }
|
---|
971 |
|
---|
972 | static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
|
---|
973 | const struct smb_filename *smb_fname,
|
---|
974 | struct smb_file_time *ft)
|
---|
975 | {
|
---|
976 | struct timespec times[2];
|
---|
977 |
|
---|
978 | if (null_timespec(ft->atime)) {
|
---|
979 | times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
|
---|
980 | times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
|
---|
981 | } else {
|
---|
982 | times[0].tv_sec = ft->atime.tv_sec;
|
---|
983 | times[0].tv_nsec = ft->atime.tv_nsec;
|
---|
984 | }
|
---|
985 |
|
---|
986 | if (null_timespec(ft->mtime)) {
|
---|
987 | times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
|
---|
988 | times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
|
---|
989 | } else {
|
---|
990 | times[1].tv_sec = ft->mtime.tv_sec;
|
---|
991 | times[1].tv_nsec = ft->mtime.tv_nsec;
|
---|
992 | }
|
---|
993 |
|
---|
994 | if ((timespec_compare(×[0],
|
---|
995 | &smb_fname->st.st_ex_atime) == 0) &&
|
---|
996 | (timespec_compare(×[1],
|
---|
997 | &smb_fname->st.st_ex_mtime) == 0)) {
|
---|
998 | return 0;
|
---|
999 | }
|
---|
1000 |
|
---|
1001 | return glfs_utimens(handle->data, smb_fname->base_name, times);
|
---|
1002 | }
|
---|
1003 |
|
---|
1004 | static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
|
---|
1005 | files_struct *fsp, off_t offset)
|
---|
1006 | {
|
---|
1007 | return glfs_ftruncate(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), offset);
|
---|
1008 | }
|
---|
1009 |
|
---|
1010 | static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
|
---|
1011 | struct files_struct *fsp,
|
---|
1012 | uint32_t mode,
|
---|
1013 | off_t offset, off_t len)
|
---|
1014 | {
|
---|
1015 | /* TODO: add support using glfs_fallocate() and glfs_zerofill() */
|
---|
1016 | errno = ENOTSUP;
|
---|
1017 | return -1;
|
---|
1018 | }
|
---|
1019 |
|
---|
1020 | static char *vfs_gluster_realpath(struct vfs_handle_struct *handle,
|
---|
1021 | const char *path)
|
---|
1022 | {
|
---|
1023 | return glfs_realpath(handle->data, path, 0);
|
---|
1024 | }
|
---|
1025 |
|
---|
1026 | static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
|
---|
1027 | files_struct *fsp, int op, off_t offset,
|
---|
1028 | off_t count, int type)
|
---|
1029 | {
|
---|
1030 | struct flock flock = { 0, };
|
---|
1031 | int ret;
|
---|
1032 |
|
---|
1033 | flock.l_type = type;
|
---|
1034 | flock.l_whence = SEEK_SET;
|
---|
1035 | flock.l_start = offset;
|
---|
1036 | flock.l_len = count;
|
---|
1037 | flock.l_pid = 0;
|
---|
1038 |
|
---|
1039 | ret = glfs_posix_lock(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), op, &flock);
|
---|
1040 |
|
---|
1041 | if (op == F_GETLK) {
|
---|
1042 | /* lock query, true if someone else has locked */
|
---|
1043 | if ((ret != -1) &&
|
---|
1044 | (flock.l_type != F_UNLCK) &&
|
---|
1045 | (flock.l_pid != 0) && (flock.l_pid != getpid()))
|
---|
1046 | return true;
|
---|
1047 | /* not me */
|
---|
1048 | return false;
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | if (ret == -1) {
|
---|
1052 | return false;
|
---|
1053 | }
|
---|
1054 |
|
---|
1055 | return true;
|
---|
1056 | }
|
---|
1057 |
|
---|
1058 | static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
|
---|
1059 | files_struct *fsp, uint32_t share_mode,
|
---|
1060 | uint32_t access_mask)
|
---|
1061 | {
|
---|
1062 | errno = ENOSYS;
|
---|
1063 | return -1;
|
---|
1064 | }
|
---|
1065 |
|
---|
1066 | static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
|
---|
1067 | files_struct *fsp, int leasetype)
|
---|
1068 | {
|
---|
1069 | errno = ENOSYS;
|
---|
1070 | return -1;
|
---|
1071 | }
|
---|
1072 |
|
---|
1073 | static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
|
---|
1074 | files_struct *fsp, off_t *poffset,
|
---|
1075 | off_t *pcount, int *ptype, pid_t *ppid)
|
---|
1076 | {
|
---|
1077 | struct flock flock = { 0, };
|
---|
1078 | int ret;
|
---|
1079 |
|
---|
1080 | flock.l_type = *ptype;
|
---|
1081 | flock.l_whence = SEEK_SET;
|
---|
1082 | flock.l_start = *poffset;
|
---|
1083 | flock.l_len = *pcount;
|
---|
1084 | flock.l_pid = 0;
|
---|
1085 |
|
---|
1086 | ret = glfs_posix_lock(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), F_GETLK, &flock);
|
---|
1087 |
|
---|
1088 | if (ret == -1) {
|
---|
1089 | return false;
|
---|
1090 | }
|
---|
1091 |
|
---|
1092 | *ptype = flock.l_type;
|
---|
1093 | *poffset = flock.l_start;
|
---|
1094 | *pcount = flock.l_len;
|
---|
1095 | *ppid = flock.l_pid;
|
---|
1096 |
|
---|
1097 | return true;
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 | static int vfs_gluster_symlink(struct vfs_handle_struct *handle,
|
---|
1101 | const char *oldpath, const char *newpath)
|
---|
1102 | {
|
---|
1103 | return glfs_symlink(handle->data, oldpath, newpath);
|
---|
1104 | }
|
---|
1105 |
|
---|
1106 | static int vfs_gluster_readlink(struct vfs_handle_struct *handle,
|
---|
1107 | const char *path, char *buf, size_t bufsiz)
|
---|
1108 | {
|
---|
1109 | return glfs_readlink(handle->data, path, buf, bufsiz);
|
---|
1110 | }
|
---|
1111 |
|
---|
1112 | static int vfs_gluster_link(struct vfs_handle_struct *handle,
|
---|
1113 | const char *oldpath, const char *newpath)
|
---|
1114 | {
|
---|
1115 | return glfs_link(handle->data, oldpath, newpath);
|
---|
1116 | }
|
---|
1117 |
|
---|
1118 | static int vfs_gluster_mknod(struct vfs_handle_struct *handle, const char *path,
|
---|
1119 | mode_t mode, SMB_DEV_T dev)
|
---|
1120 | {
|
---|
1121 | return glfs_mknod(handle->data, path, mode, dev);
|
---|
1122 | }
|
---|
1123 |
|
---|
1124 | static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
|
---|
1125 | const char *path, unsigned int flags)
|
---|
1126 | {
|
---|
1127 | errno = ENOSYS;
|
---|
1128 | return -1;
|
---|
1129 | }
|
---|
1130 |
|
---|
1131 | static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
|
---|
1132 | const char *path, const char *name,
|
---|
1133 | TALLOC_CTX *mem_ctx, char **found_name)
|
---|
1134 | {
|
---|
1135 | int ret;
|
---|
1136 | char key_buf[NAME_MAX + 64];
|
---|
1137 | char val_buf[NAME_MAX + 1];
|
---|
1138 |
|
---|
1139 | if (strlen(name) >= NAME_MAX) {
|
---|
1140 | errno = ENAMETOOLONG;
|
---|
1141 | return -1;
|
---|
1142 | }
|
---|
1143 |
|
---|
1144 | snprintf(key_buf, NAME_MAX + 64,
|
---|
1145 | "glusterfs.get_real_filename:%s", name);
|
---|
1146 |
|
---|
1147 | ret = glfs_getxattr(handle->data, path, key_buf, val_buf, NAME_MAX + 1);
|
---|
1148 | if (ret == -1) {
|
---|
1149 | if (errno == ENODATA) {
|
---|
1150 | errno = EOPNOTSUPP;
|
---|
1151 | }
|
---|
1152 | return -1;
|
---|
1153 | }
|
---|
1154 |
|
---|
1155 | *found_name = talloc_strdup(mem_ctx, val_buf);
|
---|
1156 | if (found_name[0] == NULL) {
|
---|
1157 | errno = ENOMEM;
|
---|
1158 | return -1;
|
---|
1159 | }
|
---|
1160 | return 0;
|
---|
1161 | }
|
---|
1162 |
|
---|
1163 | static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
|
---|
1164 | const char *filename)
|
---|
1165 | {
|
---|
1166 | return handle->conn->connectpath;
|
---|
1167 | }
|
---|
1168 |
|
---|
1169 | /* EA Operations */
|
---|
1170 |
|
---|
1171 | static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
|
---|
1172 | const char *path, const char *name,
|
---|
1173 | void *value, size_t size)
|
---|
1174 | {
|
---|
1175 | return glfs_getxattr(handle->data, path, name, value, size);
|
---|
1176 | }
|
---|
1177 |
|
---|
1178 | static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
|
---|
1179 | files_struct *fsp, const char *name,
|
---|
1180 | void *value, size_t size)
|
---|
1181 | {
|
---|
1182 | return glfs_fgetxattr(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), name, value, size);
|
---|
1183 | }
|
---|
1184 |
|
---|
1185 | static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
|
---|
1186 | const char *path, char *list, size_t size)
|
---|
1187 | {
|
---|
1188 | return glfs_listxattr(handle->data, path, list, size);
|
---|
1189 | }
|
---|
1190 |
|
---|
1191 | static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
|
---|
1192 | files_struct *fsp, char *list,
|
---|
1193 | size_t size)
|
---|
1194 | {
|
---|
1195 | return glfs_flistxattr(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), list, size);
|
---|
1196 | }
|
---|
1197 |
|
---|
1198 | static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
|
---|
1199 | const char *path, const char *name)
|
---|
1200 | {
|
---|
1201 | return glfs_removexattr(handle->data, path, name);
|
---|
1202 | }
|
---|
1203 |
|
---|
1204 | static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
|
---|
1205 | files_struct *fsp, const char *name)
|
---|
1206 | {
|
---|
1207 | return glfs_fremovexattr(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), name);
|
---|
1208 | }
|
---|
1209 |
|
---|
1210 | static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
|
---|
1211 | const char *path, const char *name,
|
---|
1212 | const void *value, size_t size, int flags)
|
---|
1213 | {
|
---|
1214 | return glfs_setxattr(handle->data, path, name, value, size, flags);
|
---|
1215 | }
|
---|
1216 |
|
---|
1217 | static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
|
---|
1218 | files_struct *fsp, const char *name,
|
---|
1219 | const void *value, size_t size, int flags)
|
---|
1220 | {
|
---|
1221 | return glfs_fsetxattr(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), name, value, size,
|
---|
1222 | flags);
|
---|
1223 | }
|
---|
1224 |
|
---|
1225 | /* AIO Operations */
|
---|
1226 |
|
---|
1227 | static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
|
---|
1228 | files_struct *fsp)
|
---|
1229 | {
|
---|
1230 | return false;
|
---|
1231 | }
|
---|
1232 |
|
---|
1233 | /* Offline Operations */
|
---|
1234 |
|
---|
1235 | static bool vfs_gluster_is_offline(struct vfs_handle_struct *handle,
|
---|
1236 | const struct smb_filename *fname,
|
---|
1237 | SMB_STRUCT_STAT *sbuf)
|
---|
1238 | {
|
---|
1239 | return false;
|
---|
1240 | }
|
---|
1241 |
|
---|
1242 | static int vfs_gluster_set_offline(struct vfs_handle_struct *handle,
|
---|
1243 | const struct smb_filename *fname)
|
---|
1244 | {
|
---|
1245 | errno = ENOTSUP;
|
---|
1246 | return -1;
|
---|
1247 | }
|
---|
1248 |
|
---|
1249 | /*
|
---|
1250 | Gluster ACL Format:
|
---|
1251 |
|
---|
1252 | Size = 4 (header) + N * 8 (entry)
|
---|
1253 |
|
---|
1254 | Offset Size Field (Little Endian)
|
---|
1255 | -------------------------------------
|
---|
1256 | 0-3 4-byte Version
|
---|
1257 |
|
---|
1258 | 4-5 2-byte Entry-1 tag
|
---|
1259 | 6-7 2-byte Entry-1 perm
|
---|
1260 | 8-11 4-byte Entry-1 id
|
---|
1261 |
|
---|
1262 | 12-13 2-byte Entry-2 tag
|
---|
1263 | 14-15 2-byte Entry-2 perm
|
---|
1264 | 16-19 4-byte Entry-2 id
|
---|
1265 |
|
---|
1266 | ...
|
---|
1267 |
|
---|
1268 | */
|
---|
1269 |
|
---|
1270 | /* header version */
|
---|
1271 | #define GLUSTER_ACL_VERSION 2
|
---|
1272 |
|
---|
1273 | /* perm bits */
|
---|
1274 | #define GLUSTER_ACL_READ 0x04
|
---|
1275 | #define GLUSTER_ACL_WRITE 0x02
|
---|
1276 | #define GLUSTER_ACL_EXECUTE 0x01
|
---|
1277 |
|
---|
1278 | /* tag values */
|
---|
1279 | #define GLUSTER_ACL_UNDEFINED_TAG 0x00
|
---|
1280 | #define GLUSTER_ACL_USER_OBJ 0x01
|
---|
1281 | #define GLUSTER_ACL_USER 0x02
|
---|
1282 | #define GLUSTER_ACL_GROUP_OBJ 0x04
|
---|
1283 | #define GLUSTER_ACL_GROUP 0x08
|
---|
1284 | #define GLUSTER_ACL_MASK 0x10
|
---|
1285 | #define GLUSTER_ACL_OTHER 0x20
|
---|
1286 |
|
---|
1287 | #define GLUSTER_ACL_UNDEFINED_ID (-1)
|
---|
1288 |
|
---|
1289 | #define GLUSTER_ACL_HEADER_SIZE 4
|
---|
1290 | #define GLUSTER_ACL_ENTRY_SIZE 8
|
---|
1291 |
|
---|
1292 | #define GLUSTER_ACL_SIZE(n) (GLUSTER_ACL_HEADER_SIZE + (n * GLUSTER_ACL_ENTRY_SIZE))
|
---|
1293 |
|
---|
1294 | static SMB_ACL_T mode_to_smb_acls(const struct stat *mode, TALLOC_CTX *mem_ctx)
|
---|
1295 | {
|
---|
1296 | struct smb_acl_t *result;
|
---|
1297 | int count;
|
---|
1298 |
|
---|
1299 | count = 3;
|
---|
1300 | result = sys_acl_init(mem_ctx);
|
---|
1301 | if (!result) {
|
---|
1302 | errno = ENOMEM;
|
---|
1303 | return NULL;
|
---|
1304 | }
|
---|
1305 |
|
---|
1306 | result->acl = talloc_array(result, struct smb_acl_entry, count);
|
---|
1307 | if (!result->acl) {
|
---|
1308 | errno = ENOMEM;
|
---|
1309 | talloc_free(result);
|
---|
1310 | return NULL;
|
---|
1311 | }
|
---|
1312 |
|
---|
1313 | result->count = count;
|
---|
1314 |
|
---|
1315 | result->acl[0].a_type = SMB_ACL_USER_OBJ;
|
---|
1316 | result->acl[0].a_perm = (mode->st_mode & S_IRWXU) >> 6;;
|
---|
1317 |
|
---|
1318 | result->acl[1].a_type = SMB_ACL_GROUP_OBJ;
|
---|
1319 | result->acl[1].a_perm = (mode->st_mode & S_IRWXG) >> 3;;
|
---|
1320 |
|
---|
1321 | result->acl[2].a_type = SMB_ACL_OTHER;
|
---|
1322 | result->acl[2].a_perm = mode->st_mode & S_IRWXO;;
|
---|
1323 |
|
---|
1324 | return result;
|
---|
1325 | }
|
---|
1326 |
|
---|
1327 | static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size,
|
---|
1328 | TALLOC_CTX *mem_ctx)
|
---|
1329 | {
|
---|
1330 | int count;
|
---|
1331 | size_t size;
|
---|
1332 | struct smb_acl_entry *smb_ace;
|
---|
1333 | struct smb_acl_t *result;
|
---|
1334 | int i;
|
---|
1335 | int offset;
|
---|
1336 | uint16_t tag;
|
---|
1337 | uint16_t perm;
|
---|
1338 | uint32_t id;
|
---|
1339 |
|
---|
1340 | size = xattr_size;
|
---|
1341 |
|
---|
1342 | if (size < GLUSTER_ACL_HEADER_SIZE) {
|
---|
1343 | /* ACL should be at least as big as the header (4 bytes) */
|
---|
1344 | errno = EINVAL;
|
---|
1345 | return NULL;
|
---|
1346 | }
|
---|
1347 |
|
---|
1348 | size -= GLUSTER_ACL_HEADER_SIZE; /* size of header = 4 bytes */
|
---|
1349 |
|
---|
1350 | if (size % GLUSTER_ACL_ENTRY_SIZE) {
|
---|
1351 | /* Size of entries must strictly be a multiple of
|
---|
1352 | size of an ACE (8 bytes)
|
---|
1353 | */
|
---|
1354 | errno = EINVAL;
|
---|
1355 | return NULL;
|
---|
1356 | }
|
---|
1357 |
|
---|
1358 | count = size / GLUSTER_ACL_ENTRY_SIZE;
|
---|
1359 |
|
---|
1360 | /* Version is the first 4 bytes of the ACL */
|
---|
1361 | if (IVAL(buf, 0) != GLUSTER_ACL_VERSION) {
|
---|
1362 | DEBUG(0, ("Unknown gluster ACL version: %d\n",
|
---|
1363 | IVAL(buf, 0)));
|
---|
1364 | return NULL;
|
---|
1365 | }
|
---|
1366 | offset = GLUSTER_ACL_HEADER_SIZE;
|
---|
1367 |
|
---|
1368 | result = sys_acl_init(mem_ctx);
|
---|
1369 | if (!result) {
|
---|
1370 | errno = ENOMEM;
|
---|
1371 | return NULL;
|
---|
1372 | }
|
---|
1373 |
|
---|
1374 | result->acl = talloc_array(result, struct smb_acl_entry, count);
|
---|
1375 | if (!result->acl) {
|
---|
1376 | errno = ENOMEM;
|
---|
1377 | talloc_free(result);
|
---|
1378 | return NULL;
|
---|
1379 | }
|
---|
1380 |
|
---|
1381 | result->count = count;
|
---|
1382 |
|
---|
1383 | smb_ace = result->acl;
|
---|
1384 |
|
---|
1385 | for (i = 0; i < count; i++) {
|
---|
1386 | /* TAG is the first 2 bytes of an entry */
|
---|
1387 | tag = SVAL(buf, offset);
|
---|
1388 | offset += 2;
|
---|
1389 |
|
---|
1390 | /* PERM is the next 2 bytes of an entry */
|
---|
1391 | perm = SVAL(buf, offset);
|
---|
1392 | offset += 2;
|
---|
1393 |
|
---|
1394 | /* ID is the last 4 bytes of an entry */
|
---|
1395 | id = IVAL(buf, offset);
|
---|
1396 | offset += 4;
|
---|
1397 |
|
---|
1398 | switch(tag) {
|
---|
1399 | case GLUSTER_ACL_USER:
|
---|
1400 | smb_ace->a_type = SMB_ACL_USER;
|
---|
1401 | break;
|
---|
1402 | case GLUSTER_ACL_USER_OBJ:
|
---|
1403 | smb_ace->a_type = SMB_ACL_USER_OBJ;
|
---|
1404 | break;
|
---|
1405 | case GLUSTER_ACL_GROUP:
|
---|
1406 | smb_ace->a_type = SMB_ACL_GROUP;
|
---|
1407 | break;
|
---|
1408 | case GLUSTER_ACL_GROUP_OBJ:
|
---|
1409 | smb_ace->a_type = SMB_ACL_GROUP_OBJ;
|
---|
1410 | break;
|
---|
1411 | case GLUSTER_ACL_OTHER:
|
---|
1412 | smb_ace->a_type = SMB_ACL_OTHER;
|
---|
1413 | break;
|
---|
1414 | case GLUSTER_ACL_MASK:
|
---|
1415 | smb_ace->a_type = SMB_ACL_MASK;
|
---|
1416 | break;
|
---|
1417 | default:
|
---|
1418 | DEBUG(0, ("unknown tag type %d\n", (unsigned int) tag));
|
---|
1419 | return NULL;
|
---|
1420 | }
|
---|
1421 |
|
---|
1422 |
|
---|
1423 | switch(smb_ace->a_type) {
|
---|
1424 | case SMB_ACL_USER:
|
---|
1425 | smb_ace->info.user.uid = id;
|
---|
1426 | break;
|
---|
1427 | case SMB_ACL_GROUP:
|
---|
1428 | smb_ace->info.group.gid = id;
|
---|
1429 | break;
|
---|
1430 | default:
|
---|
1431 | break;
|
---|
1432 | }
|
---|
1433 |
|
---|
1434 | smb_ace->a_perm = 0;
|
---|
1435 | smb_ace->a_perm |=
|
---|
1436 | ((perm & GLUSTER_ACL_READ) ? SMB_ACL_READ : 0);
|
---|
1437 | smb_ace->a_perm |=
|
---|
1438 | ((perm & GLUSTER_ACL_WRITE) ? SMB_ACL_WRITE : 0);
|
---|
1439 | smb_ace->a_perm |=
|
---|
1440 | ((perm & GLUSTER_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
|
---|
1441 |
|
---|
1442 | smb_ace++;
|
---|
1443 | }
|
---|
1444 |
|
---|
1445 | return result;
|
---|
1446 | }
|
---|
1447 |
|
---|
1448 |
|
---|
1449 | static int gluster_ace_cmp(const void *left, const void *right)
|
---|
1450 | {
|
---|
1451 | int ret = 0;
|
---|
1452 | uint16_t tag_left, tag_right;
|
---|
1453 | uint32_t id_left, id_right;
|
---|
1454 |
|
---|
1455 | /*
|
---|
1456 | Sorting precedence:
|
---|
1457 |
|
---|
1458 | - Smaller TAG values must be earlier.
|
---|
1459 |
|
---|
1460 | - Within same TAG, smaller identifiers must be earlier, E.g:
|
---|
1461 | UID 0 entry must be earlier than UID 200
|
---|
1462 | GID 17 entry must be earlier than GID 19
|
---|
1463 | */
|
---|
1464 |
|
---|
1465 | /* TAG is the first element in the entry */
|
---|
1466 | tag_left = SVAL(left, 0);
|
---|
1467 | tag_right = SVAL(right, 0);
|
---|
1468 |
|
---|
1469 | ret = (tag_left - tag_right);
|
---|
1470 | if (!ret) {
|
---|
1471 | /* ID is the third element in the entry, after two short
|
---|
1472 | integers (tag and perm), i.e at offset 4.
|
---|
1473 | */
|
---|
1474 | id_left = IVAL(left, 4);
|
---|
1475 | id_right = IVAL(right, 4);
|
---|
1476 | ret = id_left - id_right;
|
---|
1477 | }
|
---|
1478 |
|
---|
1479 | return ret;
|
---|
1480 | }
|
---|
1481 |
|
---|
1482 |
|
---|
1483 | static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
|
---|
1484 | {
|
---|
1485 | ssize_t size;
|
---|
1486 | struct smb_acl_entry *smb_ace;
|
---|
1487 | int i;
|
---|
1488 | int count;
|
---|
1489 | uint16_t tag;
|
---|
1490 | uint16_t perm;
|
---|
1491 | uint32_t id;
|
---|
1492 | int offset;
|
---|
1493 |
|
---|
1494 | count = theacl->count;
|
---|
1495 |
|
---|
1496 | size = GLUSTER_ACL_HEADER_SIZE + (count * GLUSTER_ACL_ENTRY_SIZE);
|
---|
1497 | if (!buf) {
|
---|
1498 | return size;
|
---|
1499 | }
|
---|
1500 |
|
---|
1501 | if (len < size) {
|
---|
1502 | errno = ERANGE;
|
---|
1503 | return -1;
|
---|
1504 | }
|
---|
1505 |
|
---|
1506 | smb_ace = theacl->acl;
|
---|
1507 |
|
---|
1508 | /* Version is the first 4 bytes of the ACL */
|
---|
1509 | SIVAL(buf, 0, GLUSTER_ACL_VERSION);
|
---|
1510 | offset = GLUSTER_ACL_HEADER_SIZE;
|
---|
1511 |
|
---|
1512 | for (i = 0; i < count; i++) {
|
---|
1513 | /* Calculate tag */
|
---|
1514 | switch(smb_ace->a_type) {
|
---|
1515 | case SMB_ACL_USER:
|
---|
1516 | tag = GLUSTER_ACL_USER;
|
---|
1517 | break;
|
---|
1518 | case SMB_ACL_USER_OBJ:
|
---|
1519 | tag = GLUSTER_ACL_USER_OBJ;
|
---|
1520 | break;
|
---|
1521 | case SMB_ACL_GROUP:
|
---|
1522 | tag = GLUSTER_ACL_GROUP;
|
---|
1523 | break;
|
---|
1524 | case SMB_ACL_GROUP_OBJ:
|
---|
1525 | tag = GLUSTER_ACL_GROUP_OBJ;
|
---|
1526 | break;
|
---|
1527 | case SMB_ACL_OTHER:
|
---|
1528 | tag = GLUSTER_ACL_OTHER;
|
---|
1529 | break;
|
---|
1530 | case SMB_ACL_MASK:
|
---|
1531 | tag = GLUSTER_ACL_MASK;
|
---|
1532 | break;
|
---|
1533 | default:
|
---|
1534 | DEBUG(0, ("Unknown tag value %d\n",
|
---|
1535 | smb_ace->a_type));
|
---|
1536 | errno = EINVAL;
|
---|
1537 | return -1;
|
---|
1538 | }
|
---|
1539 |
|
---|
1540 |
|
---|
1541 | /* Calculate id */
|
---|
1542 | switch(smb_ace->a_type) {
|
---|
1543 | case SMB_ACL_USER:
|
---|
1544 | id = smb_ace->info.user.uid;
|
---|
1545 | break;
|
---|
1546 | case SMB_ACL_GROUP:
|
---|
1547 | id = smb_ace->info.group.gid;
|
---|
1548 | break;
|
---|
1549 | default:
|
---|
1550 | id = GLUSTER_ACL_UNDEFINED_ID;
|
---|
1551 | break;
|
---|
1552 | }
|
---|
1553 |
|
---|
1554 | /* Calculate perm */
|
---|
1555 | perm = 0;
|
---|
1556 |
|
---|
1557 | perm |=
|
---|
1558 | ((smb_ace->a_perm & SMB_ACL_READ) ? GLUSTER_ACL_READ : 0);
|
---|
1559 | perm |=
|
---|
1560 | ((smb_ace->a_perm & SMB_ACL_WRITE) ? GLUSTER_ACL_WRITE : 0);
|
---|
1561 | perm |=
|
---|
1562 | ((smb_ace->a_perm & SMB_ACL_EXECUTE) ? GLUSTER_ACL_EXECUTE : 0);
|
---|
1563 |
|
---|
1564 |
|
---|
1565 | /* TAG is the first 2 bytes of an entry */
|
---|
1566 | SSVAL(buf, offset, tag);
|
---|
1567 | offset += 2;
|
---|
1568 |
|
---|
1569 | /* PERM is the next 2 bytes of an entry */
|
---|
1570 | SSVAL(buf, offset, perm);
|
---|
1571 | offset += 2;
|
---|
1572 |
|
---|
1573 | /* ID is the last 4 bytes of an entry */
|
---|
1574 | SIVAL(buf, offset, id);
|
---|
1575 | offset += 4;
|
---|
1576 |
|
---|
1577 | smb_ace++;
|
---|
1578 | }
|
---|
1579 |
|
---|
1580 | /* Skip the header, sort @count number of 8-byte entries */
|
---|
1581 | qsort(buf+GLUSTER_ACL_HEADER_SIZE, count, GLUSTER_ACL_ENTRY_SIZE,
|
---|
1582 | gluster_ace_cmp);
|
---|
1583 |
|
---|
1584 | return size;
|
---|
1585 | }
|
---|
1586 |
|
---|
1587 |
|
---|
1588 | static SMB_ACL_T vfs_gluster_sys_acl_get_file(struct vfs_handle_struct *handle,
|
---|
1589 | const char *path_p,
|
---|
1590 | SMB_ACL_TYPE_T type,
|
---|
1591 | TALLOC_CTX *mem_ctx)
|
---|
1592 | {
|
---|
1593 | struct smb_acl_t *result;
|
---|
1594 | struct stat st;
|
---|
1595 | char *buf;
|
---|
1596 | const char *key;
|
---|
1597 | ssize_t ret, size = GLUSTER_ACL_SIZE(20);
|
---|
1598 |
|
---|
1599 | switch (type) {
|
---|
1600 | case SMB_ACL_TYPE_ACCESS:
|
---|
1601 | key = "system.posix_acl_access";
|
---|
1602 | break;
|
---|
1603 | case SMB_ACL_TYPE_DEFAULT:
|
---|
1604 | key = "system.posix_acl_default";
|
---|
1605 | break;
|
---|
1606 | default:
|
---|
1607 | errno = EINVAL;
|
---|
1608 | return NULL;
|
---|
1609 | }
|
---|
1610 |
|
---|
1611 | buf = alloca(size);
|
---|
1612 | if (!buf) {
|
---|
1613 | return NULL;
|
---|
1614 | }
|
---|
1615 |
|
---|
1616 | ret = glfs_getxattr(handle->data, path_p, key, buf, size);
|
---|
1617 | if (ret == -1 && errno == ERANGE) {
|
---|
1618 | ret = glfs_getxattr(handle->data, path_p, key, 0, 0);
|
---|
1619 | if (ret > 0) {
|
---|
1620 | buf = alloca(ret);
|
---|
1621 | if (!buf) {
|
---|
1622 | return NULL;
|
---|
1623 | }
|
---|
1624 | ret = glfs_getxattr(handle->data, path_p, key, buf, ret);
|
---|
1625 | }
|
---|
1626 | }
|
---|
1627 |
|
---|
1628 | /* retrieving the ACL from the xattr has finally failed, do a
|
---|
1629 | * mode-to-acl mapping */
|
---|
1630 |
|
---|
1631 | if (ret == -1 && errno == ENODATA) {
|
---|
1632 | ret = glfs_stat(handle->data, path_p, &st);
|
---|
1633 | if (ret == 0) {
|
---|
1634 | result = mode_to_smb_acls(&st, mem_ctx);
|
---|
1635 | return result;
|
---|
1636 | }
|
---|
1637 | }
|
---|
1638 |
|
---|
1639 | if (ret <= 0) {
|
---|
1640 | return NULL;
|
---|
1641 | }
|
---|
1642 |
|
---|
1643 | result = gluster_to_smb_acl(buf, ret, mem_ctx);
|
---|
1644 |
|
---|
1645 | return result;
|
---|
1646 | }
|
---|
1647 |
|
---|
1648 | static SMB_ACL_T vfs_gluster_sys_acl_get_fd(struct vfs_handle_struct *handle,
|
---|
1649 | struct files_struct *fsp,
|
---|
1650 | TALLOC_CTX *mem_ctx)
|
---|
1651 | {
|
---|
1652 | struct smb_acl_t *result;
|
---|
1653 | struct stat st;
|
---|
1654 | ssize_t ret, size = GLUSTER_ACL_SIZE(20);
|
---|
1655 | char *buf;
|
---|
1656 | glfs_fd_t *glfd;
|
---|
1657 |
|
---|
1658 | glfd = *(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
|
---|
1659 |
|
---|
1660 | buf = alloca(size);
|
---|
1661 | if (!buf) {
|
---|
1662 | return NULL;
|
---|
1663 | }
|
---|
1664 |
|
---|
1665 | ret = glfs_fgetxattr(glfd, "system.posix_acl_access", buf, size);
|
---|
1666 | if (ret == -1 && errno == ERANGE) {
|
---|
1667 | ret = glfs_fgetxattr(glfd, "system.posix_acl_access", 0, 0);
|
---|
1668 | if (ret > 0) {
|
---|
1669 | buf = alloca(ret);
|
---|
1670 | if (!buf) {
|
---|
1671 | return NULL;
|
---|
1672 | }
|
---|
1673 | ret = glfs_fgetxattr(glfd, "system.posix_acl_access",
|
---|
1674 | buf, ret);
|
---|
1675 | }
|
---|
1676 | }
|
---|
1677 |
|
---|
1678 | /* retrieving the ACL from the xattr has finally failed, do a
|
---|
1679 | * mode-to-acl mapping */
|
---|
1680 |
|
---|
1681 | if (ret == -1 && errno == ENODATA) {
|
---|
1682 | ret = glfs_fstat(glfd, &st);
|
---|
1683 | if (ret == 0) {
|
---|
1684 | result = mode_to_smb_acls(&st, mem_ctx);
|
---|
1685 | return result;
|
---|
1686 | }
|
---|
1687 | }
|
---|
1688 |
|
---|
1689 | if (ret <= 0) {
|
---|
1690 | return NULL;
|
---|
1691 | }
|
---|
1692 |
|
---|
1693 | result = gluster_to_smb_acl(buf, ret, mem_ctx);
|
---|
1694 |
|
---|
1695 | return result;
|
---|
1696 | }
|
---|
1697 |
|
---|
1698 | static int vfs_gluster_sys_acl_set_file(struct vfs_handle_struct *handle,
|
---|
1699 | const char *name,
|
---|
1700 | SMB_ACL_TYPE_T acltype,
|
---|
1701 | SMB_ACL_T theacl)
|
---|
1702 | {
|
---|
1703 | int ret;
|
---|
1704 | const char *key;
|
---|
1705 | char *buf;
|
---|
1706 | ssize_t size;
|
---|
1707 |
|
---|
1708 | switch (acltype) {
|
---|
1709 | case SMB_ACL_TYPE_ACCESS:
|
---|
1710 | key = "system.posix_acl_access";
|
---|
1711 | break;
|
---|
1712 | case SMB_ACL_TYPE_DEFAULT:
|
---|
1713 | key = "system.posix_acl_default";
|
---|
1714 | break;
|
---|
1715 | default:
|
---|
1716 | errno = EINVAL;
|
---|
1717 | return -1;
|
---|
1718 | }
|
---|
1719 |
|
---|
1720 | size = smb_to_gluster_acl(theacl, 0, 0);
|
---|
1721 | buf = alloca(size);
|
---|
1722 |
|
---|
1723 | size = smb_to_gluster_acl(theacl, buf, size);
|
---|
1724 | if (size == -1) {
|
---|
1725 | return -1;
|
---|
1726 | }
|
---|
1727 |
|
---|
1728 | ret = glfs_setxattr(handle->data, name, key, buf, size, 0);
|
---|
1729 |
|
---|
1730 | return ret;
|
---|
1731 | }
|
---|
1732 |
|
---|
1733 | static int vfs_gluster_sys_acl_set_fd(struct vfs_handle_struct *handle,
|
---|
1734 | struct files_struct *fsp,
|
---|
1735 | SMB_ACL_T theacl)
|
---|
1736 | {
|
---|
1737 | int ret;
|
---|
1738 | char *buf;
|
---|
1739 | ssize_t size;
|
---|
1740 |
|
---|
1741 | size = smb_to_gluster_acl(theacl, 0, 0);
|
---|
1742 | buf = alloca(size);
|
---|
1743 |
|
---|
1744 | size = smb_to_gluster_acl(theacl, buf, size);
|
---|
1745 | if (size == -1) {
|
---|
1746 | return -1;
|
---|
1747 | }
|
---|
1748 |
|
---|
1749 | ret = glfs_fsetxattr(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp),
|
---|
1750 | "system.posix_acl_access", buf, size, 0);
|
---|
1751 | return ret;
|
---|
1752 | }
|
---|
1753 |
|
---|
1754 | static int vfs_gluster_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
|
---|
1755 | const char *path)
|
---|
1756 | {
|
---|
1757 | return glfs_removexattr(handle->data, path, "system.posix_acl_default");
|
---|
1758 | }
|
---|
1759 |
|
---|
1760 | static struct vfs_fn_pointers glusterfs_fns = {
|
---|
1761 |
|
---|
1762 | /* Disk Operations */
|
---|
1763 |
|
---|
1764 | .connect_fn = vfs_gluster_connect,
|
---|
1765 | .disconnect_fn = vfs_gluster_disconnect,
|
---|
1766 | .disk_free_fn = vfs_gluster_disk_free,
|
---|
1767 | .get_quota_fn = vfs_gluster_get_quota,
|
---|
1768 | .set_quota_fn = vfs_gluster_set_quota,
|
---|
1769 | .statvfs_fn = vfs_gluster_statvfs,
|
---|
1770 | .fs_capabilities_fn = vfs_gluster_fs_capabilities,
|
---|
1771 |
|
---|
1772 | .get_dfs_referrals_fn = NULL,
|
---|
1773 |
|
---|
1774 | /* Directory Operations */
|
---|
1775 |
|
---|
1776 | .opendir_fn = vfs_gluster_opendir,
|
---|
1777 | .fdopendir_fn = vfs_gluster_fdopendir,
|
---|
1778 | .readdir_fn = vfs_gluster_readdir,
|
---|
1779 | .seekdir_fn = vfs_gluster_seekdir,
|
---|
1780 | .telldir_fn = vfs_gluster_telldir,
|
---|
1781 | .rewind_dir_fn = vfs_gluster_rewinddir,
|
---|
1782 | .mkdir_fn = vfs_gluster_mkdir,
|
---|
1783 | .rmdir_fn = vfs_gluster_rmdir,
|
---|
1784 | .closedir_fn = vfs_gluster_closedir,
|
---|
1785 | .init_search_op_fn = vfs_gluster_init_search_op,
|
---|
1786 |
|
---|
1787 | /* File Operations */
|
---|
1788 |
|
---|
1789 | .open_fn = vfs_gluster_open,
|
---|
1790 | .create_file_fn = NULL,
|
---|
1791 | .close_fn = vfs_gluster_close,
|
---|
1792 | .read_fn = vfs_gluster_read,
|
---|
1793 | .pread_fn = vfs_gluster_pread,
|
---|
1794 | .pread_send_fn = vfs_gluster_pread_send,
|
---|
1795 | .pread_recv_fn = vfs_gluster_recv,
|
---|
1796 | .write_fn = vfs_gluster_write,
|
---|
1797 | .pwrite_fn = vfs_gluster_pwrite,
|
---|
1798 | .pwrite_send_fn = vfs_gluster_pwrite_send,
|
---|
1799 | .pwrite_recv_fn = vfs_gluster_recv,
|
---|
1800 | .lseek_fn = vfs_gluster_lseek,
|
---|
1801 | .sendfile_fn = vfs_gluster_sendfile,
|
---|
1802 | .recvfile_fn = vfs_gluster_recvfile,
|
---|
1803 | .rename_fn = vfs_gluster_rename,
|
---|
1804 | .fsync_fn = vfs_gluster_fsync,
|
---|
1805 | .fsync_send_fn = vfs_gluster_fsync_send,
|
---|
1806 | .fsync_recv_fn = vfs_gluster_fsync_recv,
|
---|
1807 |
|
---|
1808 | .stat_fn = vfs_gluster_stat,
|
---|
1809 | .fstat_fn = vfs_gluster_fstat,
|
---|
1810 | .lstat_fn = vfs_gluster_lstat,
|
---|
1811 | .get_alloc_size_fn = vfs_gluster_get_alloc_size,
|
---|
1812 | .unlink_fn = vfs_gluster_unlink,
|
---|
1813 |
|
---|
1814 | .chmod_fn = vfs_gluster_chmod,
|
---|
1815 | .fchmod_fn = vfs_gluster_fchmod,
|
---|
1816 | .chown_fn = vfs_gluster_chown,
|
---|
1817 | .fchown_fn = vfs_gluster_fchown,
|
---|
1818 | .lchown_fn = vfs_gluster_lchown,
|
---|
1819 | .chdir_fn = vfs_gluster_chdir,
|
---|
1820 | .getwd_fn = vfs_gluster_getwd,
|
---|
1821 | .ntimes_fn = vfs_gluster_ntimes,
|
---|
1822 | .ftruncate_fn = vfs_gluster_ftruncate,
|
---|
1823 | .fallocate_fn = vfs_gluster_fallocate,
|
---|
1824 | .lock_fn = vfs_gluster_lock,
|
---|
1825 | .kernel_flock_fn = vfs_gluster_kernel_flock,
|
---|
1826 | .linux_setlease_fn = vfs_gluster_linux_setlease,
|
---|
1827 | .getlock_fn = vfs_gluster_getlock,
|
---|
1828 | .symlink_fn = vfs_gluster_symlink,
|
---|
1829 | .readlink_fn = vfs_gluster_readlink,
|
---|
1830 | .link_fn = vfs_gluster_link,
|
---|
1831 | .mknod_fn = vfs_gluster_mknod,
|
---|
1832 | .realpath_fn = vfs_gluster_realpath,
|
---|
1833 | .chflags_fn = vfs_gluster_chflags,
|
---|
1834 | .file_id_create_fn = NULL,
|
---|
1835 | .copy_chunk_send_fn = NULL,
|
---|
1836 | .copy_chunk_recv_fn = NULL,
|
---|
1837 | .streaminfo_fn = NULL,
|
---|
1838 | .get_real_filename_fn = vfs_gluster_get_real_filename,
|
---|
1839 | .connectpath_fn = vfs_gluster_connectpath,
|
---|
1840 |
|
---|
1841 | .brl_lock_windows_fn = NULL,
|
---|
1842 | .brl_unlock_windows_fn = NULL,
|
---|
1843 | .brl_cancel_windows_fn = NULL,
|
---|
1844 | .strict_lock_fn = NULL,
|
---|
1845 | .strict_unlock_fn = NULL,
|
---|
1846 | .translate_name_fn = NULL,
|
---|
1847 | .fsctl_fn = NULL,
|
---|
1848 |
|
---|
1849 | /* NT ACL Operations */
|
---|
1850 | .fget_nt_acl_fn = NULL,
|
---|
1851 | .get_nt_acl_fn = NULL,
|
---|
1852 | .fset_nt_acl_fn = NULL,
|
---|
1853 | .audit_file_fn = NULL,
|
---|
1854 |
|
---|
1855 | /* Posix ACL Operations */
|
---|
1856 | .chmod_acl_fn = NULL, /* passthrough to default */
|
---|
1857 | .fchmod_acl_fn = NULL, /* passthrough to default */
|
---|
1858 | .sys_acl_get_file_fn = vfs_gluster_sys_acl_get_file,
|
---|
1859 | .sys_acl_get_fd_fn = vfs_gluster_sys_acl_get_fd,
|
---|
1860 | .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
|
---|
1861 | .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
|
---|
1862 | .sys_acl_set_file_fn = vfs_gluster_sys_acl_set_file,
|
---|
1863 | .sys_acl_set_fd_fn = vfs_gluster_sys_acl_set_fd,
|
---|
1864 | .sys_acl_delete_def_file_fn = vfs_gluster_sys_acl_delete_def_file,
|
---|
1865 |
|
---|
1866 | /* EA Operations */
|
---|
1867 | .getxattr_fn = vfs_gluster_getxattr,
|
---|
1868 | .fgetxattr_fn = vfs_gluster_fgetxattr,
|
---|
1869 | .listxattr_fn = vfs_gluster_listxattr,
|
---|
1870 | .flistxattr_fn = vfs_gluster_flistxattr,
|
---|
1871 | .removexattr_fn = vfs_gluster_removexattr,
|
---|
1872 | .fremovexattr_fn = vfs_gluster_fremovexattr,
|
---|
1873 | .setxattr_fn = vfs_gluster_setxattr,
|
---|
1874 | .fsetxattr_fn = vfs_gluster_fsetxattr,
|
---|
1875 |
|
---|
1876 | /* AIO Operations */
|
---|
1877 | .aio_force_fn = vfs_gluster_aio_force,
|
---|
1878 |
|
---|
1879 | /* Offline Operations */
|
---|
1880 | .is_offline_fn = vfs_gluster_is_offline,
|
---|
1881 | .set_offline_fn = vfs_gluster_set_offline,
|
---|
1882 |
|
---|
1883 | /* Durable handle Operations */
|
---|
1884 | .durable_cookie_fn = NULL,
|
---|
1885 | .durable_disconnect_fn = NULL,
|
---|
1886 | .durable_reconnect_fn = NULL,
|
---|
1887 | };
|
---|
1888 |
|
---|
1889 | NTSTATUS vfs_glusterfs_init(void);
|
---|
1890 | NTSTATUS vfs_glusterfs_init(void)
|
---|
1891 | {
|
---|
1892 | return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
|
---|
1893 | "glusterfs", &glusterfs_fns);
|
---|
1894 | }
|
---|