vfs: Implement vfs_gpfs_get_real_filename_at()
[samba.git] / source3 / modules / vfs_gpfs.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Samba VFS module for GPFS filesystem
4  *  Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
5  *  Copyright (C) Christof Schmitt 2015
6  *  Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
7  *                           and Gomati Mohanan <gomati.mohanan@in.ibm.com>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24 #include "smbd/smbd.h"
25 #include "include/smbprofile.h"
26 #include "modules/non_posix_acls.h"
27 #include "libcli/security/security.h"
28 #include "nfs4_acls.h"
29 #include "system/filesys.h"
30 #include "auth.h"
31 #include "lib/util/tevent_unix.h"
32 #include "lib/util/gpfswrap.h"
33
34 #include <gnutls/gnutls.h>
35 #include <gnutls/crypto.h>
36 #include "lib/crypto/gnutls_helpers.h"
37
38 #undef DBGC_CLASS
39 #define DBGC_CLASS DBGC_VFS
40
41 #ifndef GPFS_GETACL_NATIVE
42 #define GPFS_GETACL_NATIVE 0x00000004
43 #endif
44
45 struct gpfs_config_data {
46         struct smbacl4_vfs_params nfs4_params;
47         bool sharemodes;
48         bool leases;
49         bool hsm;
50         bool syncio;
51         bool winattr;
52         bool ftruncate;
53         bool getrealfilename;
54         bool dfreequota;
55         bool acl;
56         bool settimes;
57         bool recalls;
58         struct {
59                 bool gpfs_fstat_x;
60         } pathref_ok;
61 };
62
63 struct gpfs_fsp_extension {
64         bool offline;
65 };
66
67 static inline unsigned int gpfs_acl_flags(gpfs_acl_t *gacl)
68 {
69         if (gacl->acl_level == GPFS_ACL_LEVEL_V4FLAGS) {
70                 return gacl->v4Level1.acl_flags;
71         }
72         return 0;
73 }
74
75 static inline gpfs_ace_v4_t *gpfs_ace_ptr(gpfs_acl_t *gacl, unsigned int i)
76 {
77         if (gacl->acl_level == GPFS_ACL_LEVEL_V4FLAGS) {
78                 return &gacl->v4Level1.ace_v4[i];
79         }
80         return &gacl->ace_v4[i];
81 }
82
83 static unsigned int vfs_gpfs_access_mask_to_allow(uint32_t access_mask)
84 {
85         unsigned int allow = GPFS_SHARE_NONE;
86
87         if (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) {
88                 allow |= GPFS_SHARE_WRITE;
89         }
90         if (access_mask & (FILE_READ_DATA|FILE_EXECUTE)) {
91                 allow |= GPFS_SHARE_READ;
92         }
93
94         return allow;
95 }
96
97 static unsigned int vfs_gpfs_share_access_to_deny(uint32_t share_access)
98 {
99         unsigned int deny = GPFS_DENY_NONE;
100
101         if (!(share_access & FILE_SHARE_WRITE)) {
102                 deny |= GPFS_DENY_WRITE;
103         }
104         if (!(share_access & FILE_SHARE_READ)) {
105                 deny |= GPFS_DENY_READ;
106         }
107
108         /*
109          * GPFS_DENY_DELETE can only be set together with either
110          * GPFS_DENY_WRITE or GPFS_DENY_READ.
111          */
112         if ((deny & (GPFS_DENY_WRITE|GPFS_DENY_READ)) &&
113             !(share_access & FILE_SHARE_DELETE)) {
114                 deny |= GPFS_DENY_DELETE;
115         }
116
117         return deny;
118 }
119
120 static int set_gpfs_sharemode(files_struct *fsp, uint32_t access_mask,
121                               uint32_t share_access)
122 {
123         unsigned int allow = GPFS_SHARE_NONE;
124         unsigned int deny = GPFS_DENY_NONE;
125         int result;
126
127         if (access_mask == 0) {
128                 DBG_DEBUG("Clearing file system share mode.\n");
129         } else {
130                 allow = vfs_gpfs_access_mask_to_allow(access_mask);
131                 deny = vfs_gpfs_share_access_to_deny(share_access);
132         }
133         DBG_DEBUG("access_mask=0x%x, allow=0x%x, share_access=0x%x, "
134                   "deny=0x%x\n", access_mask, allow, share_access, deny);
135
136         result = gpfswrap_set_share(fsp_get_io_fd(fsp), allow, deny);
137         if (result == 0) {
138                 return 0;
139         }
140
141         if (errno == EACCES) {
142                 DBG_NOTICE("GPFS share mode denied for %s/%s.\n",
143                            fsp->conn->connectpath,
144                            fsp->fsp_name->base_name);
145         } else if (errno == EPERM) {
146                 DBG_ERR("Samba requested GPFS sharemode for %s/%s, but the "
147                         "GPFS file system is not configured accordingly. "
148                         "Configure file system with mmchfs -D nfs4 or "
149                         "set gpfs:sharemodes=no in Samba.\n",
150                         fsp->conn->connectpath,
151                         fsp->fsp_name->base_name);
152         } else {
153                 DBG_ERR("gpfs_set_share failed: %s\n", strerror(errno));
154         }
155
156         return result;
157 }
158
159 static int vfs_gpfs_filesystem_sharemode(vfs_handle_struct *handle,
160                                          files_struct *fsp,
161                                          uint32_t share_access,
162                                          uint32_t access_mask)
163 {
164
165         struct gpfs_config_data *config;
166         int ret = 0;
167
168         SMB_VFS_HANDLE_GET_DATA(handle, config,
169                                 struct gpfs_config_data,
170                                 return -1);
171
172         if(!config->sharemodes) {
173                 return 0;
174         }
175
176         /*
177          * A named stream fsp will have the basefile open in the fsp
178          * fd, so lacking a distinct fd for the stream we have to skip
179          * set_gpfs_sharemode for stream.
180          */
181         if (fsp_is_alternate_stream(fsp)) {
182                 DBG_NOTICE("Not requesting GPFS sharemode on stream: %s/%s\n",
183                            fsp->conn->connectpath,
184                            fsp_str_dbg(fsp));
185                 return 0;
186         }
187
188         ret = set_gpfs_sharemode(fsp, access_mask, share_access);
189
190         return ret;
191 }
192
193 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
194 {
195
196         struct gpfs_config_data *config;
197
198         SMB_VFS_HANDLE_GET_DATA(handle, config,
199                                 struct gpfs_config_data,
200                                 return -1);
201
202         if (config->sharemodes &&
203             (fsp->fsp_flags.kernel_share_modes_taken))
204         {
205                 /*
206                  * Always clear GPFS sharemode in case the actual
207                  * close gets deferred due to outstanding POSIX locks
208                  * (see fd_close_posix)
209                  */
210                 int ret = gpfswrap_set_share(fsp_get_io_fd(fsp), 0, 0);
211                 if (ret != 0) {
212                         DBG_ERR("Clearing GPFS sharemode on close failed for "
213                                 " %s/%s: %s\n",
214                                 fsp->conn->connectpath,
215                                 fsp->fsp_name->base_name,
216                                 strerror(errno));
217                 }
218         }
219
220         return SMB_VFS_NEXT_CLOSE(handle, fsp);
221 }
222
223 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
224 static int lease_type_to_gpfs(int leasetype)
225 {
226         if (leasetype == F_RDLCK) {
227                 return GPFS_LEASE_READ;
228         }
229
230         if (leasetype == F_WRLCK) {
231                 return GPFS_LEASE_WRITE;
232         }
233
234         return GPFS_LEASE_NONE;
235 }
236
237 static int vfs_gpfs_setlease(vfs_handle_struct *handle,
238                              files_struct *fsp,
239                              int leasetype)
240 {
241         struct gpfs_config_data *config;
242         int ret=0;
243
244         START_PROFILE(syscall_linux_setlease);
245
246         SMB_VFS_HANDLE_GET_DATA(handle, config,
247                                 struct gpfs_config_data,
248                                 return -1);
249
250         ret = linux_set_lease_sighandler(fsp_get_io_fd(fsp));
251         if (ret == -1) {
252                 goto failure;
253         }
254
255         if (config->leases) {
256                 int gpfs_lease_type = lease_type_to_gpfs(leasetype);
257                 int saved_errno = 0;
258
259                 /*
260                  * Ensure the lease owner is root to allow
261                  * correct delivery of lease-break signals.
262                  */
263                 become_root();
264                 ret = gpfswrap_set_lease(fsp_get_io_fd(fsp), gpfs_lease_type);
265                 if (ret < 0) {
266                         saved_errno = errno;
267                 }
268                 unbecome_root();
269
270                 if (saved_errno != 0) {
271                         errno = saved_errno;
272                 }
273         }
274
275 failure:
276         END_PROFILE(syscall_linux_setlease);
277
278         return ret;
279 }
280
281 #else /* HAVE_KERNEL_OPLOCKS_LINUX */
282
283 static int vfs_gpfs_setlease(vfs_handle_struct *handle,
284                                 files_struct *fsp,
285                                 int leasetype)
286 {
287         return ENOSYS;
288 }
289 #endif /* HAVE_KERNEL_OPLOCKS_LINUX */
290
291 static NTSTATUS vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
292                                            const struct smb_filename *path,
293                                            const char *name,
294                                            TALLOC_CTX *mem_ctx,
295                                            char **found_name)
296 {
297         int result;
298         char *full_path = NULL;
299         char *to_free = NULL;
300         char real_pathname[PATH_MAX+1], tmpbuf[PATH_MAX];
301         size_t full_path_len;
302         int buflen;
303         bool mangled;
304         struct gpfs_config_data *config;
305
306         SMB_VFS_HANDLE_GET_DATA(handle, config,
307                                 struct gpfs_config_data,
308                                 return NT_STATUS_INTERNAL_ERROR);
309
310         if (!config->getrealfilename) {
311                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
312                                                       mem_ctx, found_name);
313         }
314
315         mangled = mangle_is_mangled(name, handle->conn->params);
316         if (mangled) {
317                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
318                                                       mem_ctx, found_name);
319         }
320
321         full_path_len = full_path_tos(path->base_name, name,
322                                       tmpbuf, sizeof(tmpbuf),
323                                       &full_path, &to_free);
324         if (full_path_len == -1) {
325                 return NT_STATUS_NO_MEMORY;
326         }
327
328         buflen = sizeof(real_pathname) - 1;
329
330         result = gpfswrap_get_realfilename_path(full_path, real_pathname,
331                                                 &buflen);
332
333         TALLOC_FREE(to_free);
334
335         if ((result == -1) && (errno == ENOSYS)) {
336                 return SMB_VFS_NEXT_GET_REAL_FILENAME(
337                         handle, path, name, mem_ctx, found_name);
338         }
339
340         if (result == -1) {
341                 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
342                            strerror(errno)));
343                 return map_nt_error_from_unix(errno);
344         }
345
346         /*
347          * GPFS does not necessarily null-terminate the returned path
348          * but instead returns the buffer length in buflen.
349          */
350
351         if (buflen < sizeof(real_pathname)) {
352                 real_pathname[buflen] = '\0';
353         } else {
354                 real_pathname[sizeof(real_pathname)-1] = '\0';
355         }
356
357         DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
358                    path->base_name, name, real_pathname));
359
360         name = strrchr_m(real_pathname, '/');
361         if (name == NULL) {
362                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
363         }
364
365         *found_name = talloc_strdup(mem_ctx, name+1);
366         if (*found_name == NULL) {
367                 return NT_STATUS_NO_MEMORY;
368         }
369
370         return NT_STATUS_OK;
371 }
372
373 static NTSTATUS vfs_gpfs_get_real_filename_at(struct vfs_handle_struct *handle,
374                                               struct files_struct *dirfsp,
375                                               const char *name,
376                                               TALLOC_CTX *mem_ctx,
377                                               char **found_name)
378 {
379         int result;
380         char *full_path = NULL;
381         char *to_free = NULL;
382         char real_pathname[PATH_MAX+1], tmpbuf[PATH_MAX];
383         size_t full_path_len;
384         int buflen;
385         bool mangled;
386         struct gpfs_config_data *config;
387
388         SMB_VFS_HANDLE_GET_DATA(handle, config,
389                                 struct gpfs_config_data,
390                                 return NT_STATUS_INTERNAL_ERROR);
391
392         if (!config->getrealfilename) {
393                 return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
394                         handle, dirfsp, name, mem_ctx, found_name);
395         }
396
397         mangled = mangle_is_mangled(name, handle->conn->params);
398         if (mangled) {
399                 return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
400                         handle, dirfsp, name, mem_ctx, found_name);
401         }
402
403         full_path_len = full_path_tos(dirfsp->fsp_name->base_name, name,
404                                       tmpbuf, sizeof(tmpbuf),
405                                       &full_path, &to_free);
406         if (full_path_len == -1) {
407                 return NT_STATUS_NO_MEMORY;
408         }
409
410         buflen = sizeof(real_pathname) - 1;
411
412         result = gpfswrap_get_realfilename_path(full_path, real_pathname,
413                                                 &buflen);
414
415         TALLOC_FREE(to_free);
416
417         if ((result == -1) && (errno == ENOSYS)) {
418                 return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
419                         handle, dirfsp, name, mem_ctx, found_name);
420         }
421
422         if (result == -1) {
423                 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
424                            strerror(errno)));
425                 return map_nt_error_from_unix(errno);
426         }
427
428         /*
429          * GPFS does not necessarily null-terminate the returned path
430          * but instead returns the buffer length in buflen.
431          */
432
433         if (buflen < sizeof(real_pathname)) {
434                 real_pathname[buflen] = '\0';
435         } else {
436                 real_pathname[sizeof(real_pathname)-1] = '\0';
437         }
438
439         DBG_DEBUG("%s/%s -> %s\n",
440                   fsp_str_dbg(dirfsp),
441                   name,
442                   real_pathname);
443
444         name = strrchr_m(real_pathname, '/');
445         if (name == NULL) {
446                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
447         }
448
449         *found_name = talloc_strdup(mem_ctx, name+1);
450         if (*found_name == NULL) {
451                 return NT_STATUS_NO_MEMORY;
452         }
453
454         return NT_STATUS_OK;
455 }
456
457 static void sd2gpfs_control(uint16_t control, struct gpfs_acl *gacl)
458 {
459         unsigned int gpfs_aclflags = 0;
460         control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
461                 SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
462                 SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
463                 SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
464         gpfs_aclflags = control << 8;
465         if (!(control & SEC_DESC_DACL_PRESENT))
466                 gpfs_aclflags |= ACL4_FLAG_NULL_DACL;
467         if (!(control & SEC_DESC_SACL_PRESENT))
468                 gpfs_aclflags |= ACL4_FLAG_NULL_SACL;
469         gacl->acl_level = GPFS_ACL_LEVEL_V4FLAGS;
470         gacl->v4Level1.acl_flags = gpfs_aclflags;
471 }
472
473 static uint16_t gpfs2sd_control(unsigned int gpfs_aclflags)
474 {
475         uint16_t control = gpfs_aclflags >> 8;
476         control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
477                 SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
478                 SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
479                 SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
480         control |= SEC_DESC_SELF_RELATIVE;
481         return control;
482 }
483
484 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
485 {
486         gpfs_aclCount_t i;
487         if (gacl==NULL)
488         {
489                 DEBUG(0, ("gpfs acl is NULL\n"));
490                 return;
491         }
492
493         DEBUG(level, ("len: %d, level: %d, version: %d, nace: %d, "
494                       "control: %x\n",
495                       gacl->acl_len, gacl->acl_level, gacl->acl_version,
496                       gacl->acl_nace, gpfs_acl_flags(gacl)));
497
498         for(i=0; i<gacl->acl_nace; i++)
499         {
500                 struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
501                 DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, "
502                               "iflags:0x%x, who:%u\n",
503                               i, gace->aceType, gace->aceFlags, gace->aceMask,
504                               gace->aceIFlags, gace->aceWho));
505         }
506 }
507
508 static int gpfs_getacl_with_capability(const char *fname, int flags, void *buf)
509 {
510         int ret, saved_errno;
511
512         set_effective_capability(DAC_OVERRIDE_CAPABILITY);
513
514         ret = gpfswrap_getacl(fname, flags, buf);
515         saved_errno = errno;
516
517         drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
518
519         errno = saved_errno;
520         return ret;
521 }
522
523 /*
524  * get the ACL from GPFS, allocated on the specified mem_ctx
525  * internally retries when initial buffer was too small
526  *
527  * caller needs to cast result to either
528  * raw = yes: struct gpfs_opaque_acl
529  * raw = no: struct gpfs_acl
530  *
531  */
532 static void *vfs_gpfs_getacl(TALLOC_CTX *mem_ctx,
533                          const char *fname,
534                          const bool raw,
535                          const gpfs_aclType_t type)
536 {
537
538         void *aclbuf;
539         size_t size = 512;
540         int ret, flags;
541         unsigned int *len;
542         size_t struct_size;
543         bool use_capability = false;
544
545 again:
546
547         aclbuf = talloc_zero_size(mem_ctx, size);
548         if (aclbuf == NULL) {
549                 errno = ENOMEM;
550                 return NULL;
551         }
552
553         if (raw) {
554                 struct gpfs_opaque_acl *buf = (struct gpfs_opaque_acl *) aclbuf;
555                 buf->acl_type = type;
556                 flags = GPFS_GETACL_NATIVE;
557                 len = (unsigned int *) &(buf->acl_buffer_len);
558                 struct_size = sizeof(struct gpfs_opaque_acl);
559         } else {
560                 struct gpfs_acl *buf = (struct gpfs_acl *) aclbuf;
561                 buf->acl_type = type;
562                 buf->acl_level = GPFS_ACL_LEVEL_V4FLAGS;
563                 flags = GPFS_GETACL_STRUCT;
564                 len = &(buf->acl_len);
565                 /* reserve space for control flags in gpfs 3.5 and beyond */
566                 struct_size = sizeof(struct gpfs_acl) + sizeof(unsigned int);
567         }
568
569         /* set the length of the buffer as input value */
570         *len = size;
571
572         if (use_capability) {
573                 ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
574         } else {
575                 ret = gpfswrap_getacl(fname, flags, aclbuf);
576                 if ((ret != 0) && (errno == EACCES)) {
577                         DBG_DEBUG("Retry with DAC capability for %s\n", fname);
578                         use_capability = true;
579                         ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
580                 }
581         }
582
583         if ((ret != 0) && (errno == ENOSPC)) {
584                 /*
585                  * get the size needed to accommodate the complete buffer
586                  *
587                  * the value returned only applies to the ACL blob in the
588                  * struct so make sure to also have headroom for the first
589                  * struct members by adding room for the complete struct
590                  * (might be a few bytes too much then)
591                  */
592                 size = *len + struct_size;
593                 talloc_free(aclbuf);
594                 DEBUG(10, ("Increasing ACL buffer size to %zu\n", size));
595                 goto again;
596         }
597
598         if (ret != 0) {
599                 DEBUG(5, ("smbd_gpfs_getacl failed with %s\n",
600                           strerror(errno)));
601                 talloc_free(aclbuf);
602                 return NULL;
603         }
604
605         return aclbuf;
606 }
607
608 /* Tries to get nfs4 acls and returns SMB ACL allocated.
609  * On failure returns 1 if it got non-NFSv4 ACL to prompt 
610  * retry with POSIX ACL checks.
611  * On failure returns -1 if there is system (GPFS) error, check errno.
612  * Returns 0 on success
613  */
614 static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname,
615                              struct SMB4ACL_T **ppacl)
616 {
617         gpfs_aclCount_t i;
618         struct gpfs_acl *gacl = NULL;
619         DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
620
621         /* Get the ACL */
622         gacl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(), fname,
623                                                   false, 0);
624         if (gacl == NULL) {
625                 DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
626                            fname, strerror(errno)));
627                 if (errno == ENODATA) {
628                         /*
629                          * GPFS returns ENODATA for snapshot
630                          * directories. Retry with POSIX ACLs check.
631                          */
632                         return 1;
633                 }
634
635                 return -1;
636         }
637
638         if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
639                 DEBUG(10, ("Got non-nfsv4 acl\n"));
640                 /* Retry with POSIX ACLs check */
641                 talloc_free(gacl);
642                 return 1;
643         }
644
645         *ppacl = smb_create_smb4acl(mem_ctx);
646
647         if (gacl->acl_level == GPFS_ACL_LEVEL_V4FLAGS) {
648                 uint16_t control = gpfs2sd_control(gpfs_acl_flags(gacl));
649                 smbacl4_set_controlflags(*ppacl, control);
650         }
651
652         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d, control: %x\n",
653                    gacl->acl_len, gacl->acl_level, gacl->acl_version,
654                    gacl->acl_nace, gpfs_acl_flags(gacl)));
655
656         for (i=0; i<gacl->acl_nace; i++) {
657                 struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
658                 SMB_ACE4PROP_T smbace = { 0 };
659                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
660                            "who: %d\n", gace->aceType, gace->aceIFlags,
661                            gace->aceFlags, gace->aceMask, gace->aceWho));
662
663                 if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
664                         smbace.flags |= SMB_ACE4_ID_SPECIAL;
665                         switch (gace->aceWho) {
666                         case ACE4_SPECIAL_OWNER:
667                                 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
668                                 break;
669                         case ACE4_SPECIAL_GROUP:
670                                 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
671                                 break;
672                         case ACE4_SPECIAL_EVERYONE:
673                                 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
674                                 break;
675                         default:
676                                 DEBUG(8, ("invalid special gpfs id %d "
677                                           "ignored\n", gace->aceWho));
678                                 continue; /* don't add it */
679                         }
680                 } else {
681                         if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
682                                 smbace.who.gid = gace->aceWho;
683                         else
684                                 smbace.who.uid = gace->aceWho;
685                 }
686
687                 /* remove redundant deny entries */
688                 if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
689                         struct gpfs_ace_v4 *prev = gpfs_ace_ptr(gacl, i - 1);
690                         if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
691                             prev->aceFlags == gace->aceFlags &&
692                             prev->aceIFlags == gace->aceIFlags &&
693                             (gace->aceMask & prev->aceMask) == 0 &&
694                             gace->aceWho == prev->aceWho) {
695                                 /* it's redundant - skip it */
696                                 continue;
697                         }
698                 }
699
700                 smbace.aceType = gace->aceType;
701                 smbace.aceFlags = gace->aceFlags;
702                 smbace.aceMask = gace->aceMask;
703                 smb_add_ace4(*ppacl, &smbace);
704         }
705
706         talloc_free(gacl);
707
708         return 0;
709 }
710
711 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
712         files_struct *fsp, uint32_t security_info,
713         TALLOC_CTX *mem_ctx,
714         struct security_descriptor **ppdesc)
715 {
716         struct SMB4ACL_T *pacl = NULL;
717         int     result;
718         struct gpfs_config_data *config;
719         TALLOC_CTX *frame = talloc_stackframe();
720         NTSTATUS status;
721
722         *ppdesc = NULL;
723
724         SMB_VFS_HANDLE_GET_DATA(handle, config,
725                                 struct gpfs_config_data,
726                                 return NT_STATUS_INTERNAL_ERROR);
727
728         if (!config->acl) {
729                 status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
730                                                   mem_ctx, ppdesc);
731                 TALLOC_FREE(frame);
732                 return status;
733         }
734
735         result = gpfs_get_nfs4_acl(frame, fsp->fsp_name->base_name, &pacl);
736
737         if (result == 0) {
738                 status = smb_fget_nt_acl_nfs4(fsp, &config->nfs4_params,
739                                               security_info,
740                                               mem_ctx, ppdesc, pacl);
741                 TALLOC_FREE(frame);
742                 return status;
743         }
744
745         if (result > 0) {
746                 DEBUG(10, ("retrying with posix acl...\n"));
747                 status = posix_fget_nt_acl(fsp, security_info,
748                                            mem_ctx, ppdesc);
749                 TALLOC_FREE(frame);
750                 return status;
751         }
752
753         TALLOC_FREE(frame);
754
755         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
756         return map_nt_error_from_unix(errno);
757 }
758
759 static bool vfs_gpfs_nfs4_ace_to_gpfs_ace(SMB_ACE4PROP_T *nfs4_ace,
760                                           struct gpfs_ace_v4 *gace,
761                                           uid_t owner_uid)
762 {
763         gace->aceType = nfs4_ace->aceType;
764         gace->aceFlags = nfs4_ace->aceFlags;
765         gace->aceMask = nfs4_ace->aceMask;
766
767         if (nfs4_ace->flags & SMB_ACE4_ID_SPECIAL) {
768                 switch(nfs4_ace->who.special_id) {
769                 case SMB_ACE4_WHO_EVERYONE:
770                         gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID;
771                         gace->aceWho = ACE4_SPECIAL_EVERYONE;
772                         break;
773                 case SMB_ACE4_WHO_OWNER:
774                         /*
775                          * With GPFS it is not possible to deny ACL or
776                          * attribute access to the owner. Setting an
777                          * ACL with such an entry is not possible.
778                          * Denying ACL or attribute access for the
779                          * owner through a named ACL entry can be
780                          * stored in an ACL, it is just not effective.
781                          *
782                          * Map this case to a named entry to allow at
783                          * least setting this ACL, which will be
784                          * enforced by the smbd permission check. Do
785                          * not do this for an inheriting OWNER entry,
786                          * as this represents a CREATOR OWNER ACE. The
787                          * remaining limitation is that CREATOR OWNER
788                          * cannot deny ACL or attribute access.
789                          */
790                         if (!nfs_ace_is_inherit(nfs4_ace) &&
791                             nfs4_ace->aceType ==
792                                         SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
793                             nfs4_ace->aceMask & (SMB_ACE4_READ_ATTRIBUTES|
794                                                  SMB_ACE4_WRITE_ATTRIBUTES|
795                                                  SMB_ACE4_READ_ACL|
796                                                  SMB_ACE4_WRITE_ACL)) {
797                                 gace->aceIFlags = 0;
798                                 gace->aceWho = owner_uid;
799                         } else {
800                                 gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID;
801                                 gace->aceWho = ACE4_SPECIAL_OWNER;
802                         }
803                         break;
804                 case SMB_ACE4_WHO_GROUP:
805                         gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID;
806                         gace->aceWho = ACE4_SPECIAL_GROUP;
807                         break;
808                 default:
809                         DBG_WARNING("Unsupported special_id %d\n",
810                                     nfs4_ace->who.special_id);
811                         return false;
812                 }
813
814                 return true;
815         }
816
817         gace->aceIFlags = 0;
818         gace->aceWho = (nfs4_ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) ?
819                 nfs4_ace->who.gid : nfs4_ace->who.uid;
820
821         return true;
822 }
823
824 static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx,
825                                                 files_struct *fsp,
826                                                 struct SMB4ACL_T *smbacl,
827                                                 bool controlflags)
828 {
829         struct gpfs_acl *gacl;
830         gpfs_aclLen_t gacl_len;
831         struct SMB4ACE_T *smbace;
832
833         gacl_len = offsetof(gpfs_acl_t, ace_v4) + sizeof(unsigned int)
834                 + smb_get_naces(smbacl) * sizeof(gpfs_ace_v4_t);
835
836         gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
837         if (gacl == NULL) {
838                 DEBUG(0, ("talloc failed\n"));
839                 errno = ENOMEM;
840                 return NULL;
841         }
842
843         gacl->acl_level = GPFS_ACL_LEVEL_BASE;
844         gacl->acl_version = GPFS_ACL_VERSION_NFS4;
845         gacl->acl_type = GPFS_ACL_TYPE_NFS4;
846         gacl->acl_nace = 0; /* change later... */
847
848         if (controlflags) {
849                 gacl->acl_level = GPFS_ACL_LEVEL_V4FLAGS;
850                 sd2gpfs_control(smbacl4_get_controlflags(smbacl), gacl);
851         }
852
853         for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
854                 struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, gacl->acl_nace);
855                 SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
856                 bool add_ace;
857
858                 add_ace = vfs_gpfs_nfs4_ace_to_gpfs_ace(aceprop, gace,
859                                                         fsp->fsp_name->st.st_ex_uid);
860                 if (!add_ace) {
861                         continue;
862                 }
863
864                 gacl->acl_nace++;
865         }
866         gacl->acl_len = (char *)gpfs_ace_ptr(gacl, gacl->acl_nace)
867                 - (char *)gacl;
868         return gacl;
869 }
870
871 static bool gpfsacl_process_smbacl(vfs_handle_struct *handle,
872                                    files_struct *fsp,
873                                    struct SMB4ACL_T *smbacl)
874 {
875         int ret;
876         struct gpfs_acl *gacl;
877         TALLOC_CTX *mem_ctx = talloc_tos();
878
879         gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, true);
880         if (gacl == NULL) { /* out of memory */
881                 return False;
882         }
883         ret = gpfswrap_putacl(fsp->fsp_name->base_name,
884                               GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
885
886         if ((ret != 0) && (errno == EINVAL)) {
887                 DEBUG(10, ("Retry without nfs41 control flags\n"));
888                 talloc_free(gacl);
889                 gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, false);
890                 if (gacl == NULL) { /* out of memory */
891                         return False;
892                 }
893                 ret = gpfswrap_putacl(fsp->fsp_name->base_name,
894                                       GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA,
895                                       gacl);
896         }
897
898         if (ret != 0) {
899                 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
900                 gpfs_dumpacl(8, gacl);
901                 return False;
902         }
903
904         DEBUG(10, ("gpfs_putacl succeeded\n"));
905         return True;
906 }
907
908 static NTSTATUS gpfsacl_set_nt_acl_internal(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
909 {
910         struct gpfs_acl *acl;
911         NTSTATUS result = NT_STATUS_ACCESS_DENIED;
912
913         acl = (struct gpfs_acl*) vfs_gpfs_getacl(talloc_tos(),
914                                                  fsp->fsp_name->base_name,
915                                                  false, 0);
916         if (acl == NULL) {
917                 return map_nt_error_from_unix(errno);
918         }
919
920         if (acl->acl_version == GPFS_ACL_VERSION_NFS4) {
921                 struct gpfs_config_data *config;
922
923                 if (lp_parm_bool(fsp->conn->params->service, "gpfs",
924                                  "refuse_dacl_protected", false)
925                     && (psd->type&SEC_DESC_DACL_PROTECTED)) {
926                         DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
927                         talloc_free(acl);
928                         return NT_STATUS_NOT_SUPPORTED;
929                 }
930
931                 SMB_VFS_HANDLE_GET_DATA(handle, config,
932                                         struct gpfs_config_data,
933                                         return NT_STATUS_INTERNAL_ERROR);
934
935                 result = smb_set_nt_acl_nfs4(handle,
936                         fsp, &config->nfs4_params, security_info_sent, psd,
937                         gpfsacl_process_smbacl);
938         } else { /* assume POSIX ACL - by default... */
939                 result = set_nt_acl(fsp, security_info_sent, psd);
940         }
941
942         talloc_free(acl);
943         return result;
944 }
945
946 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
947 {
948         struct gpfs_config_data *config;
949
950         SMB_VFS_HANDLE_GET_DATA(handle, config,
951                                 struct gpfs_config_data,
952                                 return NT_STATUS_INTERNAL_ERROR);
953
954         if (!config->acl) {
955                 return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
956         }
957
958         return gpfsacl_set_nt_acl_internal(handle, fsp, security_info_sent, psd);
959 }
960
961 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl, TALLOC_CTX *mem_ctx)
962 {
963         SMB_ACL_T result;
964         gpfs_aclCount_t i;
965
966         result = sys_acl_init(mem_ctx);
967         if (result == NULL) {
968                 errno = ENOMEM;
969                 return NULL;
970         }
971
972         result->count = pacl->acl_nace;
973         result->acl = talloc_realloc(result, result->acl, struct smb_acl_entry,
974                                      result->count);
975         if (result->acl == NULL) {
976                 TALLOC_FREE(result);
977                 errno = ENOMEM;
978                 return NULL;
979         }
980
981         for (i=0; i<pacl->acl_nace; i++) {
982                 struct smb_acl_entry *ace = &result->acl[i];
983                 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
984
985                 DEBUG(10, ("Converting type %d id %lu perm %x\n",
986                            (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
987                            (int)g_ace->ace_perm));
988
989                 switch (g_ace->ace_type) {
990                 case GPFS_ACL_USER:
991                         ace->a_type = SMB_ACL_USER;
992                         ace->info.user.uid = (uid_t)g_ace->ace_who;
993                         break;
994                 case GPFS_ACL_USER_OBJ:
995                         ace->a_type = SMB_ACL_USER_OBJ;
996                         break;
997                 case GPFS_ACL_GROUP:
998                         ace->a_type = SMB_ACL_GROUP;
999                         ace->info.group.gid = (gid_t)g_ace->ace_who;
1000                         break;
1001                 case GPFS_ACL_GROUP_OBJ:
1002                         ace->a_type = SMB_ACL_GROUP_OBJ;
1003                         break;
1004                 case GPFS_ACL_OTHER:
1005                         ace->a_type = SMB_ACL_OTHER;
1006                         break;
1007                 case GPFS_ACL_MASK:
1008                         ace->a_type = SMB_ACL_MASK;
1009                         break;
1010                 default:
1011                         DEBUG(10, ("Got invalid ace_type: %d\n",
1012                                    g_ace->ace_type));
1013                         TALLOC_FREE(result);
1014                         errno = EINVAL;
1015                         return NULL;
1016                 }
1017
1018                 ace->a_perm = 0;
1019                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
1020                         SMB_ACL_READ : 0;
1021                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
1022                         SMB_ACL_WRITE : 0;
1023                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
1024                         SMB_ACL_EXECUTE : 0;
1025
1026                 DEBUGADD(10, ("Converted to %d perm %x\n",
1027                               ace->a_type, ace->a_perm));
1028         }
1029
1030         return result;
1031 }
1032
1033 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type,
1034                                        TALLOC_CTX *mem_ctx)
1035 {
1036         struct gpfs_acl *pacl;
1037         SMB_ACL_T result = NULL;
1038
1039         pacl = vfs_gpfs_getacl(talloc_tos(), path, false, type);
1040
1041         if (pacl == NULL) {
1042                 DEBUG(10, ("vfs_gpfs_getacl failed for %s with %s\n",
1043                            path, strerror(errno)));
1044                 if (errno == 0) {
1045                         errno = EINVAL;
1046                 }
1047                 goto done;
1048         }
1049
1050         if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
1051                 DEBUG(10, ("Got acl version %d, expected %d\n",
1052                            pacl->acl_version, GPFS_ACL_VERSION_POSIX));
1053                 errno = EINVAL;
1054                 goto done;
1055         }
1056
1057         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
1058                    pacl->acl_len, pacl->acl_level, pacl->acl_version,
1059                    pacl->acl_nace));
1060
1061         result = gpfs2smb_acl(pacl, mem_ctx);
1062         if (result != NULL) {
1063                 errno = 0;
1064         }
1065
1066  done:
1067
1068         if (pacl != NULL) {
1069                 talloc_free(pacl);
1070         }
1071         if (errno != 0) {
1072                 TALLOC_FREE(result);
1073         }
1074         return result;
1075 }
1076
1077 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
1078                                         files_struct *fsp,
1079                                         SMB_ACL_TYPE_T type,
1080                                         TALLOC_CTX *mem_ctx)
1081 {
1082         gpfs_aclType_t gpfs_type;
1083         struct gpfs_config_data *config;
1084
1085         SMB_VFS_HANDLE_GET_DATA(handle, config,
1086                                 struct gpfs_config_data,
1087                                 return NULL);
1088
1089         if (!config->acl) {
1090                 return SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, type, mem_ctx);
1091         }
1092
1093         switch(type) {
1094         case SMB_ACL_TYPE_ACCESS:
1095                 gpfs_type = GPFS_ACL_TYPE_ACCESS;
1096                 break;
1097         case SMB_ACL_TYPE_DEFAULT:
1098                 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
1099                 break;
1100         default:
1101                 DEBUG(0, ("Got invalid type: %d\n", type));
1102                 smb_panic("exiting");
1103         }
1104         return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
1105                                      gpfs_type, mem_ctx);
1106 }
1107
1108 static int gpfsacl_sys_acl_blob_get_fd(vfs_handle_struct *handle,
1109                                       files_struct *fsp,
1110                                       TALLOC_CTX *mem_ctx,
1111                                       char **blob_description,
1112                                       DATA_BLOB *blob)
1113 {
1114         struct gpfs_config_data *config;
1115         struct gpfs_opaque_acl *acl = NULL;
1116         DATA_BLOB aclblob;
1117         int result;
1118
1119         SMB_VFS_HANDLE_GET_DATA(handle, config,
1120                                 struct gpfs_config_data,
1121                                 return -1);
1122
1123         if (!config->acl) {
1124                 return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
1125                                                         blob_description, blob);
1126         }
1127
1128         errno = 0;
1129         acl = (struct gpfs_opaque_acl *) vfs_gpfs_getacl(mem_ctx,
1130                                                 fsp->fsp_name->base_name,
1131                                                 true,
1132                                                 GPFS_ACL_TYPE_NFS4);
1133
1134         if (errno) {
1135                 DEBUG(5, ("vfs_gpfs_getacl finished with errno %d: %s\n",
1136                                         errno, strerror(errno)));
1137
1138                 /* EINVAL means POSIX ACL, bail out on other cases */
1139                 if (errno != EINVAL) {
1140                         return -1;
1141                 }
1142         }
1143
1144         if (acl != NULL) {
1145                 /*
1146                  * file has NFSv4 ACL
1147                  *
1148                  * we only need the actual ACL blob here
1149                  * acl_version will always be NFS4 because we asked
1150                  * for NFS4
1151                  * acl_type is only used for POSIX ACLs
1152                  */
1153                 aclblob.data = (uint8_t*) acl->acl_var_data;
1154                 aclblob.length = acl->acl_buffer_len;
1155
1156                 *blob_description = talloc_strdup(mem_ctx, "gpfs_nfs4_acl");
1157                 if (!*blob_description) {
1158                         talloc_free(acl);
1159                         errno = ENOMEM;
1160                         return -1;
1161                 }
1162
1163                 result = non_posix_sys_acl_blob_get_fd_helper(handle, fsp,
1164                                                               aclblob, mem_ctx,
1165                                                               blob);
1166
1167                 talloc_free(acl);
1168                 return result;
1169         }
1170
1171         /* fall back to POSIX ACL */
1172         return posix_sys_acl_blob_get_fd(handle, fsp, mem_ctx,
1173                                          blob_description, blob);
1174 }
1175
1176 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
1177                                      SMB_ACL_TYPE_T type)
1178 {
1179         gpfs_aclLen_t len;
1180         struct gpfs_acl *result;
1181         int i;
1182
1183         DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
1184
1185         len = offsetof(gpfs_acl_t, ace_v1) + (pacl->count) *
1186                 sizeof(gpfs_ace_v1_t);
1187
1188         result = (struct gpfs_acl *)SMB_MALLOC(len);
1189         if (result == NULL) {
1190                 errno = ENOMEM;
1191                 return result;
1192         }
1193
1194         result->acl_len = len;
1195         result->acl_level = 0;
1196         result->acl_version = GPFS_ACL_VERSION_POSIX;
1197         result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
1198                 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
1199         result->acl_nace = pacl->count;
1200
1201         for (i=0; i<pacl->count; i++) {
1202                 const struct smb_acl_entry *ace = &pacl->acl[i];
1203                 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
1204
1205                 DEBUG(10, ("Converting type %d perm %x\n",
1206                            (int)ace->a_type, (int)ace->a_perm));
1207
1208                 g_ace->ace_perm = 0;
1209
1210                 switch(ace->a_type) {
1211                 case SMB_ACL_USER:
1212                         g_ace->ace_type = GPFS_ACL_USER;
1213                         g_ace->ace_who = (gpfs_uid_t)ace->info.user.uid;
1214                         break;
1215                 case SMB_ACL_USER_OBJ:
1216                         g_ace->ace_type = GPFS_ACL_USER_OBJ;
1217                         g_ace->ace_perm |= ACL_PERM_CONTROL;
1218                         g_ace->ace_who = 0;
1219                         break;
1220                 case SMB_ACL_GROUP:
1221                         g_ace->ace_type = GPFS_ACL_GROUP;
1222                         g_ace->ace_who = (gpfs_uid_t)ace->info.group.gid;
1223                         break;
1224                 case SMB_ACL_GROUP_OBJ:
1225                         g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
1226                         g_ace->ace_who = 0;
1227                         break;
1228                 case SMB_ACL_MASK:
1229                         g_ace->ace_type = GPFS_ACL_MASK;
1230                         g_ace->ace_perm = 0x8f;
1231                         g_ace->ace_who = 0;
1232                         break;
1233                 case SMB_ACL_OTHER:
1234                         g_ace->ace_type = GPFS_ACL_OTHER;
1235                         g_ace->ace_who = 0;
1236                         break;
1237                 default:
1238                         DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
1239                         errno = EINVAL;
1240                         SAFE_FREE(result);
1241                         return NULL;
1242                 }
1243
1244                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
1245                         ACL_PERM_READ : 0;
1246                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
1247                         ACL_PERM_WRITE : 0;
1248                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
1249                         ACL_PERM_EXECUTE : 0;
1250
1251                 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
1252                               g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
1253         }
1254
1255         return result;
1256 }
1257
1258 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
1259                                   files_struct *fsp,
1260                                   SMB_ACL_TYPE_T type,
1261                                   SMB_ACL_T theacl)
1262 {
1263         struct gpfs_config_data *config;
1264         struct gpfs_acl *gpfs_acl = NULL;
1265         int result;
1266
1267         SMB_VFS_HANDLE_GET_DATA(handle, config,
1268                                 struct gpfs_config_data,
1269                                 return -1);
1270
1271         if (!config->acl) {
1272                 return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, type, theacl);
1273         }
1274
1275         gpfs_acl = smb2gpfs_acl(theacl, type);
1276         if (gpfs_acl == NULL) {
1277                 return -1;
1278         }
1279
1280         /*
1281          * This is no longer a handle based call.
1282          */
1283         result = gpfswrap_putacl(fsp->fsp_name->base_name,
1284                                  GPFS_PUTACL_STRUCT|GPFS_ACL_SAMBA,
1285                                  gpfs_acl);
1286         SAFE_FREE(gpfs_acl);
1287         return result;
1288 }
1289
1290 static int gpfsacl_sys_acl_delete_def_fd(vfs_handle_struct *handle,
1291                                 files_struct *fsp)
1292 {
1293         struct gpfs_config_data *config;
1294
1295         SMB_VFS_HANDLE_GET_DATA(handle, config,
1296                                 struct gpfs_config_data,
1297                                 return -1);
1298
1299         if (!config->acl) {
1300                 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FD(handle, fsp);
1301         }
1302
1303         errno = ENOTSUP;
1304         return -1;
1305 }
1306
1307
1308 /*
1309  * Assumed: mode bits are shiftable and standard
1310  * Output: the new aceMask field for an smb nfs4 ace
1311  */
1312 static uint32_t gpfsacl_mask_filter(uint32_t aceType, uint32_t aceMask, uint32_t rwx)
1313 {
1314         const uint32_t posix_nfs4map[3] = {
1315                 SMB_ACE4_EXECUTE, /* execute */
1316                 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
1317                 SMB_ACE4_READ_DATA /* read */
1318         };
1319         int     i;
1320         uint32_t        posix_mask = 0x01;
1321         uint32_t        posix_bit;
1322         uint32_t        nfs4_bits;
1323
1324         for(i=0; i<3; i++) {
1325                 nfs4_bits = posix_nfs4map[i];
1326                 posix_bit = rwx & posix_mask;
1327
1328                 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
1329                         if (posix_bit)
1330                                 aceMask |= nfs4_bits;
1331                         else
1332                                 aceMask &= ~nfs4_bits;
1333                 } else {
1334                         /* add deny bits when suitable */
1335                         if (!posix_bit)
1336                                 aceMask |= nfs4_bits;
1337                         else
1338                                 aceMask &= ~nfs4_bits;
1339                 } /* other ace types are unexpected */
1340
1341                 posix_mask <<= 1;
1342         }
1343
1344         return aceMask;
1345 }
1346
1347 static int gpfsacl_emu_chmod(vfs_handle_struct *handle,
1348                              const struct smb_filename *fname, mode_t mode)
1349 {
1350         char *path = fname->base_name;
1351         struct SMB4ACL_T *pacl = NULL;
1352         int     result;
1353         bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
1354         int     i;
1355         files_struct fake_fsp = { 0 }; /* TODO: rationalize parametrization */
1356         struct SMB4ACE_T *smbace;
1357         TALLOC_CTX *frame = talloc_stackframe();
1358
1359         DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
1360
1361         result = gpfs_get_nfs4_acl(frame, path, &pacl);
1362         if (result) {
1363                 TALLOC_FREE(frame);
1364                 return result;
1365         }
1366
1367         if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
1368                 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
1369         }
1370
1371         for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
1372                 SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
1373                 uint32_t        specid = ace->who.special_id;
1374
1375                 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
1376                     ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
1377                     specid <= SMB_ACE4_WHO_EVERYONE) {
1378
1379                         uint32_t newMask;
1380
1381                         if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
1382                                 haveAllowEntry[specid] = True;
1383
1384                         /* mode >> 6 for @owner, mode >> 3 for @group,
1385                          * mode >> 0 for @everyone */
1386                         newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
1387                                                       mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
1388                         if (ace->aceMask!=newMask) {
1389                                 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
1390                                            path, ace->aceMask, newMask, specid));
1391                         }
1392                         ace->aceMask = newMask;
1393                 }
1394         }
1395
1396         /* make sure we have at least ALLOW entries
1397          * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
1398          * - if necessary
1399          */
1400         for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
1401                 SMB_ACE4PROP_T ace = { 0 };
1402
1403                 if (haveAllowEntry[i]==True)
1404                         continue;
1405
1406                 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
1407                 ace.flags |= SMB_ACE4_ID_SPECIAL;
1408                 ace.who.special_id = i;
1409
1410                 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
1411                         ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
1412
1413                 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
1414                                                   mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
1415
1416                 /* don't add unnecessary aces */
1417                 if (!ace.aceMask)
1418                         continue;
1419
1420                 /* we add it to the END - as windows expects allow aces */
1421                 smb_add_ace4(pacl, &ace);
1422                 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
1423                            path, mode, i, ace.aceMask));
1424         }
1425
1426         /* don't add complementary DENY ACEs here */
1427         fake_fsp.fsp_name = synthetic_smb_fname(frame,
1428                                                 path,
1429                                                 NULL,
1430                                                 NULL,
1431                                                 fname->twrp,
1432                                                 0);
1433         if (fake_fsp.fsp_name == NULL) {
1434                 errno = ENOMEM;
1435                 TALLOC_FREE(frame);
1436                 return -1;
1437         }
1438         /* put the acl */
1439         if (gpfsacl_process_smbacl(handle, &fake_fsp, pacl) == False) {
1440                 TALLOC_FREE(frame);
1441                 return -1;
1442         }
1443
1444         TALLOC_FREE(frame);
1445         return 0; /* ok for [f]chmod */
1446 }
1447
1448 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
1449 {
1450                  SMB_STRUCT_STAT st;
1451                  int rc;
1452
1453                  if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
1454                          return -1;
1455                  }
1456
1457                  /* avoid chmod() if possible, to preserve acls */
1458                  if ((st.st_ex_mode & ~S_IFMT) == mode) {
1459                          return 0;
1460                  }
1461
1462                  rc = gpfsacl_emu_chmod(handle, fsp->fsp_name,
1463                                         mode);
1464                  if (rc == 1)
1465                          return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1466                  return rc;
1467 }
1468
1469 static uint32_t vfs_gpfs_winattrs_to_dosmode(unsigned int winattrs)
1470 {
1471         uint32_t dosmode = 0;
1472
1473         if (winattrs & GPFS_WINATTR_ARCHIVE){
1474                 dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1475         }
1476         if (winattrs & GPFS_WINATTR_HIDDEN){
1477                 dosmode |= FILE_ATTRIBUTE_HIDDEN;
1478         }
1479         if (winattrs & GPFS_WINATTR_SYSTEM){
1480                 dosmode |= FILE_ATTRIBUTE_SYSTEM;
1481         }
1482         if (winattrs & GPFS_WINATTR_READONLY){
1483                 dosmode |= FILE_ATTRIBUTE_READONLY;
1484         }
1485         if (winattrs & GPFS_WINATTR_SPARSE_FILE) {
1486                 dosmode |= FILE_ATTRIBUTE_SPARSE;
1487         }
1488         if (winattrs & GPFS_WINATTR_OFFLINE) {
1489                 dosmode |= FILE_ATTRIBUTE_OFFLINE;
1490         }
1491
1492         return dosmode;
1493 }
1494
1495 static unsigned int vfs_gpfs_dosmode_to_winattrs(uint32_t dosmode)
1496 {
1497         unsigned int winattrs = 0;
1498
1499         if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
1500                 winattrs |= GPFS_WINATTR_ARCHIVE;
1501         }
1502         if (dosmode & FILE_ATTRIBUTE_HIDDEN){
1503                 winattrs |= GPFS_WINATTR_HIDDEN;
1504         }
1505         if (dosmode & FILE_ATTRIBUTE_SYSTEM){
1506                 winattrs |= GPFS_WINATTR_SYSTEM;
1507         }
1508         if (dosmode & FILE_ATTRIBUTE_READONLY){
1509                 winattrs |= GPFS_WINATTR_READONLY;
1510         }
1511         if (dosmode & FILE_ATTRIBUTE_SPARSE) {
1512                 winattrs |= GPFS_WINATTR_SPARSE_FILE;
1513         }
1514         if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
1515                 winattrs |= GPFS_WINATTR_OFFLINE;
1516         }
1517
1518         return winattrs;
1519 }
1520
1521 static struct timespec gpfs_timestruc64_to_timespec(struct gpfs_timestruc64 g)
1522 {
1523         return (struct timespec) { .tv_sec = g.tv_sec, .tv_nsec = g.tv_nsec };
1524 }
1525
1526 static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle,
1527                                              struct files_struct *fsp,
1528                                              uint32_t *dosmode)
1529 {
1530         struct gpfs_config_data *config;
1531         int fd = fsp_get_pathref_fd(fsp);
1532         char buf[PATH_MAX];
1533         const char *p = NULL;
1534         struct gpfs_iattr64 iattr = { };
1535         unsigned int litemask = 0;
1536         struct timespec ts;
1537         int ret;
1538
1539         SMB_VFS_HANDLE_GET_DATA(handle, config,
1540                                 struct gpfs_config_data,
1541                                 return NT_STATUS_INTERNAL_ERROR);
1542
1543         if (!config->winattr) {
1544                 return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1545         }
1546
1547         if (fsp->fsp_flags.is_pathref && !config->pathref_ok.gpfs_fstat_x) {
1548                 if (fsp->fsp_flags.have_proc_fds) {
1549                         p = sys_proc_fd_path(fd, buf, sizeof(buf));
1550                         if (p == NULL) {
1551                                 return NT_STATUS_NO_MEMORY;
1552                         }
1553                 } else {
1554                         p = fsp->fsp_name->base_name;
1555                 }
1556         }
1557
1558         if (p != NULL) {
1559                 ret = gpfswrap_stat_x(p, &litemask, &iattr, sizeof(iattr));
1560         } else {
1561                 ret = gpfswrap_fstat_x(fd, &litemask, &iattr, sizeof(iattr));
1562         }
1563         if (ret == -1 && errno == ENOSYS) {
1564                 return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1565         }
1566
1567         if (ret == -1 && errno == EACCES) {
1568                 int saved_errno = 0;
1569
1570                 /*
1571                  * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
1572                  * an Existing File" FILE_LIST_DIRECTORY on a directory implies
1573                  * FILE_READ_ATTRIBUTES for directory entries. Being able to
1574                  * open a file implies FILE_LIST_DIRECTORY.
1575                  */
1576
1577                 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
1578
1579                 if (p != NULL) {
1580                         ret = gpfswrap_stat_x(p,
1581                                               &litemask,
1582                                               &iattr,
1583                                               sizeof(iattr));
1584                 } else {
1585                         ret = gpfswrap_fstat_x(fd,
1586                                                &litemask,
1587                                                &iattr,
1588                                                sizeof(iattr));
1589                 }
1590                 if (ret == -1) {
1591                         saved_errno = errno;
1592                 }
1593
1594                 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
1595
1596                 if (saved_errno != 0) {
1597                         errno = saved_errno;
1598                 }
1599         }
1600
1601         if (ret == -1) {
1602                 DBG_WARNING("Getting winattrs failed for %s: %s\n",
1603                             fsp->fsp_name->base_name, strerror(errno));
1604                 return map_nt_error_from_unix(errno);
1605         }
1606
1607         ts = gpfs_timestruc64_to_timespec(iattr.ia_createtime);
1608
1609         *dosmode |= vfs_gpfs_winattrs_to_dosmode(iattr.ia_winflags);
1610         update_stat_ex_create_time(&fsp->fsp_name->st, ts);
1611
1612         return NT_STATUS_OK;
1613 }
1614
1615 static NTSTATUS vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct *handle,
1616                                              struct files_struct *fsp,
1617                                              uint32_t dosmode)
1618 {
1619         struct gpfs_config_data *config;
1620         struct gpfs_winattr attrs = { };
1621         int ret;
1622
1623         SMB_VFS_HANDLE_GET_DATA(handle, config,
1624                                 struct gpfs_config_data,
1625                                 return NT_STATUS_INTERNAL_ERROR);
1626
1627         if (!config->winattr) {
1628                 return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
1629         }
1630
1631         attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode);
1632
1633         if (!fsp->fsp_flags.is_pathref) {
1634                 ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp),
1635                                             GPFS_WINATTR_SET_ATTRS, &attrs);
1636                 if (ret == -1) {
1637                         DBG_WARNING("Setting winattrs failed for %s: %s\n",
1638                                     fsp_str_dbg(fsp), strerror(errno));
1639                         return map_nt_error_from_unix(errno);
1640                 }
1641                 return NT_STATUS_OK;
1642         }
1643
1644         if (fsp->fsp_flags.have_proc_fds) {
1645                 int fd = fsp_get_pathref_fd(fsp);
1646                 const char *p = NULL;
1647                 char buf[PATH_MAX];
1648
1649                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
1650                 if (p == NULL) {
1651                         return NT_STATUS_NO_MEMORY;
1652                 }
1653
1654                 ret = gpfswrap_set_winattrs_path(p,
1655                                                  GPFS_WINATTR_SET_ATTRS,
1656                                                  &attrs);
1657                 if (ret == -1) {
1658                         DBG_WARNING("Setting winattrs failed for [%s][%s]: %s\n",
1659                                     p, fsp_str_dbg(fsp), strerror(errno));
1660                         return map_nt_error_from_unix(errno);
1661                 }
1662                 return NT_STATUS_OK;
1663         }
1664
1665         /*
1666          * This is no longer a handle based call.
1667          */
1668         ret = gpfswrap_set_winattrs_path(fsp->fsp_name->base_name,
1669                                          GPFS_WINATTR_SET_ATTRS,
1670                                          &attrs);
1671         if (ret == -1) {
1672                 DBG_WARNING("Setting winattrs failed for [%s]: %s\n",
1673                             fsp_str_dbg(fsp), strerror(errno));
1674                 return map_nt_error_from_unix(errno);
1675         }
1676
1677         return NT_STATUS_OK;
1678 }
1679
1680 static int stat_with_capability(struct vfs_handle_struct *handle,
1681                                 struct smb_filename *smb_fname, int flag)
1682 {
1683         int fd = -1;
1684         NTSTATUS status;
1685         struct smb_filename *dir_name = NULL;
1686         struct smb_filename *rel_name = NULL;
1687         struct stat st;
1688         int ret = -1;
1689
1690         status = SMB_VFS_PARENT_PATHNAME(handle->conn,
1691                                          talloc_tos(),
1692                                          smb_fname,
1693                                          &dir_name,
1694                                          &rel_name);
1695         if (!NT_STATUS_IS_OK(status)) {
1696                 errno = map_errno_from_nt_status(status);
1697                 return -1;
1698         }
1699
1700         fd = open(dir_name->base_name, O_RDONLY, 0);
1701         if (fd == -1) {
1702                 TALLOC_FREE(dir_name);
1703                 return -1;
1704         }
1705
1706         set_effective_capability(DAC_OVERRIDE_CAPABILITY);
1707         ret = fstatat(fd, rel_name->base_name, &st, flag);
1708         drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
1709
1710         TALLOC_FREE(dir_name);
1711         close(fd);
1712
1713         if (ret == 0) {
1714                 init_stat_ex_from_stat(
1715                         &smb_fname->st, &st,
1716                         lp_fake_directory_create_times(SNUM(handle->conn)));
1717         }
1718
1719         return ret;
1720 }
1721
1722 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1723                          struct smb_filename *smb_fname)
1724 {
1725         int ret;
1726
1727         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1728         if (ret == -1 && errno == EACCES) {
1729                 DEBUG(10, ("Trying stat with capability for %s\n",
1730                            smb_fname->base_name));
1731                 ret = stat_with_capability(handle, smb_fname, 0);
1732         }
1733         return ret;
1734 }
1735
1736 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1737                           struct smb_filename *smb_fname)
1738 {
1739         int ret;
1740
1741         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1742         if (ret == -1 && errno == EACCES) {
1743                 DEBUG(10, ("Trying lstat with capability for %s\n",
1744                            smb_fname->base_name));
1745                 ret = stat_with_capability(handle, smb_fname,
1746                                            AT_SYMLINK_NOFOLLOW);
1747         }
1748         return ret;
1749 }
1750
1751 static void timespec_to_gpfs_time(struct timespec ts, gpfs_timestruc_t *gt,
1752                                   int idx, int *flags)
1753 {
1754         if (!is_omit_timespec(&ts)) {
1755                 *flags |= 1 << idx;
1756                 gt[idx].tv_sec = ts.tv_sec;
1757                 gt[idx].tv_nsec = ts.tv_nsec;
1758                 DEBUG(10, ("Setting GPFS time %d, flags 0x%x\n", idx, *flags));
1759         }
1760 }
1761
1762 static int smbd_gpfs_set_times(struct files_struct *fsp,
1763                                struct smb_file_time *ft)
1764 {
1765         gpfs_timestruc_t gpfs_times[4];
1766         int flags = 0;
1767         int rc;
1768
1769         ZERO_ARRAY(gpfs_times);
1770         timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags);
1771         timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags);
1772         /* No good mapping from LastChangeTime to ctime, not storing */
1773         timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags);
1774
1775         if (!flags) {
1776                 DBG_DEBUG("nothing to do, return to avoid EINVAL\n");
1777                 return 0;
1778         }
1779
1780         if (!fsp->fsp_flags.is_pathref) {
1781                 rc = gpfswrap_set_times(fsp_get_io_fd(fsp), flags, gpfs_times);
1782                 if (rc != 0) {
1783                         DBG_WARNING("gpfs_set_times(%s) failed: %s\n",
1784                                     fsp_str_dbg(fsp), strerror(errno));
1785                 }
1786                 return rc;
1787         }
1788
1789
1790         if (fsp->fsp_flags.have_proc_fds) {
1791                 int fd = fsp_get_pathref_fd(fsp);
1792                 const char *p = NULL;
1793                 char buf[PATH_MAX];
1794
1795                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
1796                 if (p == NULL) {
1797                         return -1;
1798                 }
1799
1800                 rc = gpfswrap_set_times_path(buf, flags, gpfs_times);
1801                 if (rc != 0) {
1802                         DBG_WARNING("gpfs_set_times_path(%s,%s) failed: %s\n",
1803                                     fsp_str_dbg(fsp), p, strerror(errno));
1804                 }
1805                 return rc;
1806         }
1807
1808         /*
1809          * This is no longer a handle based call.
1810          */
1811
1812         rc = gpfswrap_set_times_path(fsp->fsp_name->base_name,
1813                                      flags,
1814                                      gpfs_times);
1815         if (rc != 0) {
1816                 DBG_WARNING("gpfs_set_times_path(%s) failed: %s\n",
1817                             fsp_str_dbg(fsp), strerror(errno));
1818         }
1819         return rc;
1820 }
1821
1822 static int vfs_gpfs_fntimes(struct vfs_handle_struct *handle,
1823                 files_struct *fsp,
1824                 struct smb_file_time *ft)
1825 {
1826
1827         struct gpfs_winattr attrs;
1828         int ret;
1829         struct gpfs_config_data *config;
1830
1831         SMB_VFS_HANDLE_GET_DATA(handle,
1832                                 config,
1833                                 struct gpfs_config_data,
1834                                 return -1);
1835
1836         /* Try to use gpfs_set_times if it is enabled and available */
1837         if (config->settimes) {
1838                 return smbd_gpfs_set_times(fsp, ft);
1839         }
1840
1841         DBG_DEBUG("gpfs_set_times() not available or disabled, "
1842                   "use ntimes and winattr\n");
1843
1844         ret = SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
1845         if (ret == -1) {
1846                 /* don't complain if access was denied */
1847                 if (errno != EPERM && errno != EACCES) {
1848                         DBG_WARNING("SMB_VFS_NEXT_FNTIMES failed: %s",
1849                                     strerror(errno));
1850                 }
1851                 return -1;
1852         }
1853
1854         if (is_omit_timespec(&ft->create_time)) {
1855                 DBG_DEBUG("Create Time is NULL\n");
1856                 return 0;
1857         }
1858
1859         if (!config->winattr) {
1860                 return 0;
1861         }
1862
1863         attrs.winAttrs = 0;
1864         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1865         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1866
1867         if (!fsp->fsp_flags.is_pathref) {
1868                 ret = gpfswrap_set_winattrs(fsp_get_io_fd(fsp),
1869                                             GPFS_WINATTR_SET_CREATION_TIME,
1870                                             &attrs);
1871                 if (ret == -1 && errno != ENOSYS) {
1872                         DBG_WARNING("Set GPFS ntimes failed %d\n", ret);
1873                         return -1;
1874                 }
1875                 return ret;
1876         }
1877
1878         if (fsp->fsp_flags.have_proc_fds) {
1879                 int fd = fsp_get_pathref_fd(fsp);
1880                 const char *p = NULL;
1881                 char buf[PATH_MAX];
1882
1883                 p = sys_proc_fd_path(fd, buf, sizeof(buf));
1884                 if (p == NULL) {
1885                         return -1;
1886                 }
1887
1888                 ret = gpfswrap_set_winattrs_path(p,
1889                                                  GPFS_WINATTR_SET_CREATION_TIME,
1890                                                  &attrs);
1891                 if (ret == -1 && errno != ENOSYS) {
1892                         DBG_WARNING("Set GPFS ntimes failed %d\n", ret);
1893                         return -1;
1894                 }
1895                 return ret;
1896         }
1897
1898         /*
1899          * This is no longer a handle based call.
1900          */
1901         ret = gpfswrap_set_winattrs_path(fsp->fsp_name->base_name,
1902                                          GPFS_WINATTR_SET_CREATION_TIME,
1903                                          &attrs);
1904         if (ret == -1 && errno != ENOSYS) {
1905                 DBG_WARNING("Set GPFS ntimes failed %d\n", ret);
1906                 return -1;
1907         }
1908
1909         return 0;
1910 }
1911
1912 static int vfs_gpfs_fallocate(struct vfs_handle_struct *handle,
1913                               struct files_struct *fsp, uint32_t mode,
1914                               off_t offset, off_t len)
1915 {
1916         if (mode == (VFS_FALLOCATE_FL_PUNCH_HOLE|VFS_FALLOCATE_FL_KEEP_SIZE) &&
1917             !fsp->fsp_flags.is_sparse &&
1918             lp_strict_allocate(SNUM(fsp->conn))) {
1919                 /*
1920                  * This is from a ZERO_DATA request on a non-sparse
1921                  * file. GPFS does not support FL_KEEP_SIZE and thus
1922                  * cannot fill the whole again in the subsequent
1923                  * fallocate(FL_KEEP_SIZE). Deny this FL_PUNCH_HOLE
1924                  * call to not end up with a hole in a non-sparse
1925                  * file.
1926                  */
1927                 errno = ENOTSUP;
1928                 return -1;
1929         }
1930
1931         return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
1932 }
1933
1934 static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
1935                                 off_t len)
1936 {
1937         int result;
1938         struct gpfs_config_data *config;
1939
1940         SMB_VFS_HANDLE_GET_DATA(handle, config,
1941                                 struct gpfs_config_data,
1942                                 return -1);
1943
1944         if (!config->ftruncate) {
1945                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1946         }
1947
1948         result = gpfswrap_ftruncate(fsp_get_io_fd(fsp), len);
1949         if ((result == -1) && (errno == ENOSYS)) {
1950                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1951         }
1952         return result;
1953 }
1954
1955 static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
1956                                 const struct smb_filename *fname,
1957                                 SMB_STRUCT_STAT *sbuf)
1958 {
1959         struct gpfs_winattr attrs;
1960         struct gpfs_config_data *config;
1961         int ret;
1962
1963         SMB_VFS_HANDLE_GET_DATA(handle, config,
1964                                 struct gpfs_config_data,
1965                                 return false);
1966
1967         if (!config->winattr) {
1968                 return false;
1969         }
1970
1971         ret = gpfswrap_get_winattrs_path(fname->base_name, &attrs);
1972         if (ret == -1) {
1973                 return false;
1974         }
1975
1976         if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
1977                 DBG_DEBUG("%s is offline\n", fname->base_name);
1978                 return true;
1979         }
1980
1981         DBG_DEBUG("%s is online\n", fname->base_name);
1982         return false;
1983 }
1984
1985 static bool vfs_gpfs_fsp_is_offline(struct vfs_handle_struct *handle,
1986                                     struct files_struct *fsp)
1987 {
1988         struct gpfs_fsp_extension *ext;
1989
1990         ext = VFS_FETCH_FSP_EXTENSION(handle, fsp);
1991         if (ext == NULL) {
1992                 /*
1993                  * Something bad happened, always ask.
1994                  */
1995                 return vfs_gpfs_is_offline(handle, fsp->fsp_name,
1996                                            &fsp->fsp_name->st);
1997         }
1998
1999         if (ext->offline) {
2000                 /*
2001                  * As long as it's offline, ask.
2002                  */
2003                 ext->offline = vfs_gpfs_is_offline(handle, fsp->fsp_name,
2004                                                    &fsp->fsp_name->st);
2005         }
2006
2007         return ext->offline;
2008 }
2009
2010 static bool vfs_gpfs_aio_force(struct vfs_handle_struct *handle,
2011                                struct files_struct *fsp)
2012 {
2013         return vfs_gpfs_fsp_is_offline(handle, fsp);
2014 }
2015
2016 static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd,
2017                                  files_struct *fsp, const DATA_BLOB *hdr,
2018                                  off_t offset, size_t n)
2019 {
2020         if (vfs_gpfs_fsp_is_offline(handle, fsp)) {
2021                 errno = ENOSYS;
2022                 return -1;
2023         }
2024         return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
2025 }
2026
2027 #ifdef O_PATH
2028 static int vfs_gpfs_check_pathref_fstat_x(struct gpfs_config_data *config,
2029                                           struct connection_struct *conn)
2030 {
2031         struct gpfs_iattr64 iattr = {0};
2032         unsigned int litemask = 0;
2033         int saved_errno;
2034         int fd;
2035         int ret;
2036
2037         fd = open(conn->connectpath, O_PATH);
2038         if (fd == -1) {
2039                 DBG_ERR("openat() of share with O_PATH failed: %s\n",
2040                         strerror(errno));
2041                 return -1;
2042         }
2043
2044         ret = gpfswrap_fstat_x(fd, &litemask, &iattr, sizeof(iattr));
2045         if (ret == 0) {
2046                 close(fd);
2047                 config->pathref_ok.gpfs_fstat_x = true;
2048                 return 0;
2049         }
2050
2051         saved_errno = errno;
2052         ret = close(fd);
2053         if (ret != 0) {
2054                 DBG_ERR("close failed: %s\n", strerror(errno));
2055                 return -1;
2056         }
2057
2058         if (saved_errno != EBADF) {
2059                 DBG_ERR("gpfswrap_fstat_x() of O_PATH handle failed: %s\n",
2060                         strerror(saved_errno));
2061                 return -1;
2062         }
2063
2064         return 0;
2065 }
2066 #endif
2067
2068 static int vfs_gpfs_check_pathref(struct gpfs_config_data *config,
2069                                   struct connection_struct *conn)
2070 {
2071 #ifndef O_PATH
2072         /*
2073          * This code path leaves all struct gpfs_config_data.pathref_ok members
2074          * initialized to false.
2075          */
2076         return 0;
2077 #else
2078         int ret;
2079
2080         ret = vfs_gpfs_check_pathref_fstat_x(config, conn);
2081         if (ret != 0) {
2082                 return -1;
2083         }
2084
2085         return 0;
2086 #endif
2087 }
2088
2089 static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
2090                             const char *service, const char *user)
2091 {
2092         struct gpfs_config_data *config;
2093         int ret;
2094         bool check_fstype;
2095
2096         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
2097         if (ret < 0) {
2098                 return ret;
2099         }
2100
2101         if (IS_IPC(handle->conn)) {
2102                 return 0;
2103         }
2104
2105         gpfswrap_lib_init(0);
2106
2107         config = talloc_zero(handle->conn, struct gpfs_config_data);
2108         if (!config) {
2109                 DEBUG(0, ("talloc_zero() failed\n"));
2110                 errno = ENOMEM;
2111                 return -1;
2112         }
2113
2114         check_fstype = lp_parm_bool(SNUM(handle->conn), "gpfs",
2115                                     "check_fstype", true);
2116
2117         if (check_fstype) {
2118                 const char *connectpath = handle->conn->connectpath;
2119                 struct statfs buf = { 0 };
2120
2121                 ret = statfs(connectpath, &buf);
2122                 if (ret != 0) {
2123                         DBG_ERR("statfs failed for share %s at path %s: %s\n",
2124                                 service, connectpath, strerror(errno));
2125                         TALLOC_FREE(config);
2126                         return ret;
2127                 }
2128
2129                 if (buf.f_type != GPFS_SUPER_MAGIC) {
2130                         DBG_ERR("SMB share %s, path %s not in GPFS file system."
2131                                 " statfs magic: 0x%jx\n",
2132                                 service,
2133                                 connectpath,
2134                                 (uintmax_t)buf.f_type);
2135                         errno = EINVAL;
2136                         TALLOC_FREE(config);
2137                         return -1;
2138                 }
2139         }
2140
2141         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
2142         if (ret < 0) {
2143                 TALLOC_FREE(config);
2144                 return ret;
2145         }
2146
2147         config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
2148                                         "sharemodes", true);
2149
2150         config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
2151                                         "leases", true);
2152
2153         config->hsm = lp_parm_bool(SNUM(handle->conn), "gpfs",
2154                                    "hsm", false);
2155
2156         config->syncio = lp_parm_bool(SNUM(handle->conn), "gpfs",
2157                                       "syncio", false);
2158
2159         config->winattr = lp_parm_bool(SNUM(handle->conn), "gpfs",
2160                                        "winattr", false);
2161
2162         config->ftruncate = lp_parm_bool(SNUM(handle->conn), "gpfs",
2163                                          "ftruncate", true);
2164
2165         config->getrealfilename = lp_parm_bool(SNUM(handle->conn), "gpfs",
2166                                                "getrealfilename", true);
2167
2168         config->dfreequota = lp_parm_bool(SNUM(handle->conn), "gpfs",
2169                                           "dfreequota", false);
2170
2171         config->acl = lp_parm_bool(SNUM(handle->conn), "gpfs", "acl", true);
2172
2173         config->settimes = lp_parm_bool(SNUM(handle->conn), "gpfs",
2174                                         "settimes", true);
2175         config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs",
2176                                        "recalls", true);
2177
2178         ret = vfs_gpfs_check_pathref(config, handle->conn);
2179         if (ret != 0) {
2180                 DBG_ERR("vfs_gpfs_check_pathref() on [%s] failed\n",
2181                         handle->conn->connectpath);
2182                 TALLOC_FREE(config);
2183                 return -1;
2184         }
2185
2186         SMB_VFS_HANDLE_SET_DATA(handle, config,
2187                                 NULL, struct gpfs_config_data,
2188                                 return -1);
2189
2190         if (config->leases) {
2191                 /*
2192                  * GPFS lease code is based on kernel oplock code
2193                  * so make sure it is turned on
2194                  */
2195                 if (!lp_kernel_oplocks(SNUM(handle->conn))) {
2196                         DEBUG(5, ("Enabling kernel oplocks for "
2197                                   "gpfs:leases to work\n"));
2198                         lp_do_parameter(SNUM(handle->conn), "kernel oplocks",
2199                                         "true");
2200                 }
2201
2202                 /*
2203                  * as the kernel does not properly support Level II oplocks
2204                  * and GPFS leases code is based on kernel infrastructure, we
2205                  * need to turn off Level II oplocks if gpfs:leases is enabled
2206                  */
2207                 if (lp_level2_oplocks(SNUM(handle->conn))) {
2208                         DEBUG(5, ("gpfs:leases are enabled, disabling "
2209                                   "Level II oplocks\n"));
2210                         lp_do_parameter(SNUM(handle->conn), "level2 oplocks",
2211                                         "false");
2212                 }
2213         }
2214
2215         /*
2216          * Unless we have an async implementation of get_dos_attributes turn
2217          * this off.
2218          */
2219         lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
2220
2221         return 0;
2222 }
2223
2224 static int get_gpfs_quota(const char *pathname, int type, int id,
2225                           struct gpfs_quotaInfo *qi)
2226 {
2227         int ret;
2228
2229         ret = gpfswrap_quotactl(pathname, GPFS_QCMD(Q_GETQUOTA, type), id, qi);
2230
2231         if (ret) {
2232                 if (errno == GPFS_E_NO_QUOTA_INST) {
2233                         DEBUG(10, ("Quotas disabled on GPFS filesystem.\n"));
2234                 } else if (errno != ENOSYS) {
2235                         DEBUG(0, ("Get quota failed, type %d, id, %d, "
2236                                   "errno %d.\n", type, id, errno));
2237                 }
2238
2239                 return ret;
2240         }
2241
2242         DEBUG(10, ("quota type %d, id %d, blk u:%lld h:%lld s:%lld gt:%u\n",
2243                    type, id, qi->blockUsage, qi->blockHardLimit,
2244                    qi->blockSoftLimit, qi->blockGraceTime));
2245
2246         return ret;
2247 }
2248
2249 static void vfs_gpfs_disk_free_quota(struct gpfs_quotaInfo qi, time_t cur_time,
2250                                      uint64_t *dfree, uint64_t *dsize)
2251 {
2252         uint64_t usage, limit;
2253
2254         /*
2255          * The quota reporting is done in units of 1024 byte blocks, but
2256          * sys_fsusage uses units of 512 byte blocks, adjust the block number
2257          * accordingly. Also filter possibly negative usage counts from gpfs.
2258          */
2259         usage = qi.blockUsage < 0 ? 0 : (uint64_t)qi.blockUsage * 2;
2260         limit = (uint64_t)qi.blockHardLimit * 2;
2261
2262         /*
2263          * When the grace time for the exceeded soft block quota has been
2264          * exceeded, the soft block quota becomes an additional hard limit.
2265          */
2266         if (qi.blockSoftLimit &&
2267             qi.blockGraceTime && cur_time > qi.blockGraceTime) {
2268                 /* report disk as full */
2269                 *dfree = 0;
2270                 *dsize = MIN(*dsize, usage);
2271         }
2272
2273         if (!qi.blockHardLimit)
2274                 return;
2275
2276         if (usage >= limit) {
2277                 /* report disk as full */
2278                 *dfree = 0;
2279                 *dsize = MIN(*dsize, usage);
2280
2281         } else {
2282                 /* limit has not been reached, determine "free space" */
2283                 *dfree = MIN(*dfree, limit - usage);
2284                 *dsize = MIN(*dsize, limit);
2285         }
2286 }
2287
2288 static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle,
2289                                 const struct smb_filename *smb_fname,
2290                                 uint64_t *bsize,
2291                                 uint64_t *dfree,
2292                                 uint64_t *dsize)
2293 {
2294         struct security_unix_token *utok;
2295         struct gpfs_quotaInfo qi_user = { 0 }, qi_group = { 0 };
2296         struct gpfs_config_data *config;
2297         int err;
2298         time_t cur_time;
2299
2300         SMB_VFS_HANDLE_GET_DATA(handle, config, struct gpfs_config_data,
2301                                 return (uint64_t)-1);
2302         if (!config->dfreequota) {
2303                 return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2304                                               bsize, dfree, dsize);
2305         }
2306
2307         err = sys_fsusage(smb_fname->base_name, dfree, dsize);
2308         if (err) {
2309                 DEBUG (0, ("Could not get fs usage, errno %d\n", errno));
2310                 return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2311                                               bsize, dfree, dsize);
2312         }
2313
2314         /* sys_fsusage returns units of 512 bytes */
2315         *bsize = 512;
2316
2317         DEBUG(10, ("fs dfree %llu, dsize %llu\n",
2318                    (unsigned long long)*dfree, (unsigned long long)*dsize));
2319
2320         utok = handle->conn->session_info->unix_token;
2321
2322         err = get_gpfs_quota(smb_fname->base_name,
2323                         GPFS_USRQUOTA, utok->uid, &qi_user);
2324         if (err) {
2325                 return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2326                                               bsize, dfree, dsize);
2327         }
2328
2329         /*
2330          * If new files created under this folder get this folder's
2331          * GID, then available space is governed by the quota of the
2332          * folder's GID, not the primary group of the creating user.
2333          */
2334         if (VALID_STAT(smb_fname->st) &&
2335             S_ISDIR(smb_fname->st.st_ex_mode) &&
2336             smb_fname->st.st_ex_mode & S_ISGID) {
2337                 become_root();
2338                 err = get_gpfs_quota(smb_fname->base_name, GPFS_GRPQUOTA,
2339                                      smb_fname->st.st_ex_gid, &qi_group);
2340                 unbecome_root();
2341
2342         } else {
2343                 err = get_gpfs_quota(smb_fname->base_name, GPFS_GRPQUOTA,
2344                                      utok->gid, &qi_group);
2345         }
2346
2347         if (err) {
2348                 return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2349                                               bsize, dfree, dsize);
2350         }
2351
2352         cur_time = time(NULL);
2353
2354         /* Adjust free space and size according to quota limits. */
2355         vfs_gpfs_disk_free_quota(qi_user, cur_time, dfree, dsize);
2356         vfs_gpfs_disk_free_quota(qi_group, cur_time, dfree, dsize);
2357
2358         return *dfree / 2;
2359 }
2360
2361 static int vfs_gpfs_get_quota(vfs_handle_struct *handle,
2362                                 const struct smb_filename *smb_fname,
2363                                 enum SMB_QUOTA_TYPE qtype,
2364                                 unid_t id,
2365                                 SMB_DISK_QUOTA *dq)
2366 {
2367         switch(qtype) {
2368                 /*
2369                  * User/group quota are being used for disk-free
2370                  * determination, which in this module is done directly
2371                  * by the disk-free function. It's important that this
2372                  * module does not return wrong quota values by mistake,
2373                  * which would modify the correct values set by disk-free.
2374                  * User/group quota are also being used for processing
2375                  * NT_TRANSACT_GET_USER_QUOTA in smb1 protocol, which is
2376                  * currently not supported by this module.
2377                  */
2378                 case SMB_USER_QUOTA_TYPE:
2379                 case SMB_GROUP_QUOTA_TYPE:
2380                         errno = ENOSYS;
2381                         return -1;
2382                 default:
2383                         return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname,
2384                                         qtype, id, dq);
2385         }
2386 }
2387
2388 static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
2389                                       enum timestamp_set_resolution *p_ts_res)
2390 {
2391         struct gpfs_config_data *config;
2392         uint32_t next;
2393
2394         next = SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res);
2395
2396         SMB_VFS_HANDLE_GET_DATA(handle, config,
2397                                 struct gpfs_config_data,
2398                                 return next);
2399
2400         if (config->hsm) {
2401                 next |= FILE_SUPPORTS_REMOTE_STORAGE;
2402         }
2403         return next;
2404 }
2405
2406 static int vfs_gpfs_openat(struct vfs_handle_struct *handle,
2407                            const struct files_struct *dirfsp,
2408                            const struct smb_filename *smb_fname,
2409                            files_struct *fsp,
2410                            int flags,
2411                            mode_t mode)
2412 {
2413         struct gpfs_config_data *config = NULL;
2414         struct gpfs_fsp_extension *ext = NULL;
2415         int ret;
2416
2417         SMB_VFS_HANDLE_GET_DATA(handle, config,
2418                                 struct gpfs_config_data,
2419                                 return -1);
2420
2421         if (config->hsm && !config->recalls &&
2422             !fsp->fsp_flags.is_pathref &&
2423             vfs_gpfs_fsp_is_offline(handle, fsp))
2424         {
2425                 DBG_DEBUG("Refusing access to offline file %s\n",
2426                           fsp_str_dbg(fsp));
2427                 errno = EACCES;
2428                 return -1;
2429         }
2430
2431         if (config->syncio) {
2432                 flags |= O_SYNC;
2433         }
2434
2435         ext = VFS_ADD_FSP_EXTENSION(handle, fsp, struct gpfs_fsp_extension,
2436                                     NULL);
2437         if (ext == NULL) {
2438                 errno = ENOMEM;
2439                 return -1;
2440         }
2441
2442         /*
2443          * Assume the file is offline until gpfs tells us it's online.
2444          */
2445         *ext = (struct gpfs_fsp_extension) { .offline = true };
2446
2447         ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
2448         if (ret == -1) {
2449                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
2450         }
2451         return ret;
2452 }
2453
2454 static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
2455                               void *data, size_t n, off_t offset)
2456 {
2457         ssize_t ret;
2458         bool was_offline;
2459
2460         was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2461
2462         ret = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
2463
2464         if ((ret != -1) && was_offline) {
2465                 notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
2466                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2467                              fsp->fsp_name->base_name);
2468         }
2469
2470         return ret;
2471 }
2472
2473 struct vfs_gpfs_pread_state {
2474         struct files_struct *fsp;
2475         ssize_t ret;
2476         bool was_offline;
2477         struct vfs_aio_state vfs_aio_state;
2478 };
2479
2480 static void vfs_gpfs_pread_done(struct tevent_req *subreq);
2481
2482 static struct tevent_req *vfs_gpfs_pread_send(struct vfs_handle_struct *handle,
2483                                               TALLOC_CTX *mem_ctx,
2484                                               struct tevent_context *ev,
2485                                               struct files_struct *fsp,
2486                                               void *data, size_t n,
2487                                               off_t offset)
2488 {
2489         struct tevent_req *req, *subreq;
2490         struct vfs_gpfs_pread_state *state;
2491
2492         req = tevent_req_create(mem_ctx, &state, struct vfs_gpfs_pread_state);
2493         if (req == NULL) {
2494                 return NULL;
2495         }
2496         state->was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2497         state->fsp = fsp;
2498         subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
2499                                          n, offset);
2500         if (tevent_req_nomem(subreq, req)) {
2501                 return tevent_req_post(req, ev);
2502         }
2503         tevent_req_set_callback(subreq, vfs_gpfs_pread_done, req);
2504         return req;
2505 }
2506
2507 static void vfs_gpfs_pread_done(struct tevent_req *subreq)
2508 {
2509         struct tevent_req *req = tevent_req_callback_data(
2510                 subreq, struct tevent_req);
2511         struct vfs_gpfs_pread_state *state = tevent_req_data(
2512                 req, struct vfs_gpfs_pread_state);
2513
2514         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
2515         TALLOC_FREE(subreq);
2516         tevent_req_done(req);
2517 }
2518
2519 static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req,
2520                                    struct vfs_aio_state *vfs_aio_state)
2521 {
2522         struct vfs_gpfs_pread_state *state = tevent_req_data(
2523                 req, struct vfs_gpfs_pread_state);
2524         struct files_struct *fsp = state->fsp;
2525
2526         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2527                 return -1;
2528         }
2529         *vfs_aio_state = state->vfs_aio_state;
2530
2531         if ((state->ret != -1) && state->was_offline) {
2532                 DEBUG(10, ("sending notify\n"));
2533                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
2534                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2535                              fsp->fsp_name->base_name);
2536         }
2537
2538         return state->ret;
2539 }
2540
2541 static ssize_t vfs_gpfs_pwrite(vfs_handle_struct *handle, files_struct *fsp,
2542                                const void *data, size_t n, off_t offset)
2543 {
2544         ssize_t ret;
2545         bool was_offline;
2546
2547         was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2548
2549         ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2550
2551         if ((ret != -1) && was_offline) {
2552                 notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
2553                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2554                              fsp->fsp_name->base_name);
2555         }
2556
2557         return ret;
2558 }
2559
2560 struct vfs_gpfs_pwrite_state {
2561         struct files_struct *fsp;
2562         ssize_t ret;
2563         bool was_offline;
2564         struct vfs_aio_state vfs_aio_state;
2565 };
2566
2567 static void vfs_gpfs_pwrite_done(struct tevent_req *subreq);
2568
2569 static struct tevent_req *vfs_gpfs_pwrite_send(
2570         struct vfs_handle_struct *handle,
2571         TALLOC_CTX *mem_ctx,
2572         struct tevent_context *ev,
2573         struct files_struct *fsp,
2574         const void *data, size_t n,
2575         off_t offset)
2576 {
2577         struct tevent_req *req, *subreq;
2578         struct vfs_gpfs_pwrite_state *state;
2579
2580         req = tevent_req_create(mem_ctx, &state, struct vfs_gpfs_pwrite_state);
2581         if (req == NULL) {
2582                 return NULL;
2583         }
2584         state->was_offline = vfs_gpfs_fsp_is_offline(handle, fsp);
2585         state->fsp = fsp;
2586         subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
2587                                          n, offset);
2588         if (tevent_req_nomem(subreq, req)) {
2589                 return tevent_req_post(req, ev);
2590         }
2591         tevent_req_set_callback(subreq, vfs_gpfs_pwrite_done, req);
2592         return req;
2593 }
2594
2595 static void vfs_gpfs_pwrite_done(struct tevent_req *subreq)
2596 {
2597         struct tevent_req *req = tevent_req_callback_data(
2598                 subreq, struct tevent_req);
2599         struct vfs_gpfs_pwrite_state *state = tevent_req_data(
2600                 req, struct vfs_gpfs_pwrite_state);
2601
2602         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
2603         TALLOC_FREE(subreq);
2604         tevent_req_done(req);
2605 }
2606
2607 static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req,
2608                                     struct vfs_aio_state *vfs_aio_state)
2609 {
2610         struct vfs_gpfs_pwrite_state *state = tevent_req_data(
2611                 req, struct vfs_gpfs_pwrite_state);
2612         struct files_struct *fsp = state->fsp;
2613
2614         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2615                 return -1;
2616         }
2617         *vfs_aio_state = state->vfs_aio_state;
2618
2619         if ((state->ret != -1) && state->was_offline) {
2620                 DEBUG(10, ("sending notify\n"));
2621                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
2622                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
2623                              fsp->fsp_name->base_name);
2624         }
2625
2626         return state->ret;
2627 }
2628
2629
2630 static struct vfs_fn_pointers vfs_gpfs_fns = {
2631         .connect_fn = vfs_gpfs_connect,
2632         .disk_free_fn = vfs_gpfs_disk_free,
2633         .get_quota_fn = vfs_gpfs_get_quota,
2634         .fs_capabilities_fn = vfs_gpfs_capabilities,
2635         .filesystem_sharemode_fn = vfs_gpfs_filesystem_sharemode,
2636         .linux_setlease_fn = vfs_gpfs_setlease,
2637         .get_real_filename_fn = vfs_gpfs_get_real_filename,
2638         .get_real_filename_at_fn = vfs_gpfs_get_real_filename_at,
2639         .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
2640         .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
2641         .fget_dos_attributes_fn = vfs_gpfs_fget_dos_attributes,
2642         .fset_dos_attributes_fn = vfs_gpfs_fset_dos_attributes,
2643         .fget_nt_acl_fn = gpfsacl_fget_nt_acl,
2644         .fset_nt_acl_fn = gpfsacl_fset_nt_acl,
2645         .sys_acl_get_fd_fn = gpfsacl_sys_acl_get_fd,
2646         .sys_acl_blob_get_fd_fn = gpfsacl_sys_acl_blob_get_fd,
2647         .sys_acl_set_fd_fn = gpfsacl_sys_acl_set_fd,
2648         .sys_acl_delete_def_fd_fn = gpfsacl_sys_acl_delete_def_fd,
2649         .fchmod_fn = vfs_gpfs_fchmod,
2650         .close_fn = vfs_gpfs_close,
2651         .stat_fn = vfs_gpfs_stat,
2652         .lstat_fn = vfs_gpfs_lstat,
2653         .fntimes_fn = vfs_gpfs_fntimes,
2654         .aio_force_fn = vfs_gpfs_aio_force,
2655         .sendfile_fn = vfs_gpfs_sendfile,
2656         .fallocate_fn = vfs_gpfs_fallocate,
2657         .openat_fn = vfs_gpfs_openat,
2658         .pread_fn = vfs_gpfs_pread,
2659         .pread_send_fn = vfs_gpfs_pread_send,
2660         .pread_recv_fn = vfs_gpfs_pread_recv,
2661         .pwrite_fn = vfs_gpfs_pwrite,
2662         .pwrite_send_fn = vfs_gpfs_pwrite_send,
2663         .pwrite_recv_fn = vfs_gpfs_pwrite_recv,
2664         .ftruncate_fn = vfs_gpfs_ftruncate
2665 };
2666
2667 static_decl_vfs;
2668 NTSTATUS vfs_gpfs_init(TALLOC_CTX *ctx)
2669 {
2670         int ret;
2671
2672         ret = gpfswrap_init();
2673         if (ret != 0) {
2674                 DEBUG(1, ("Could not initialize GPFS library wrapper\n"));
2675         }
2676
2677         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
2678                                 &vfs_gpfs_fns);
2679 }