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