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