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