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