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