s3/vfs_gpfs: map SPARSE attribute to/from WINATTRs, too
[mat/samba.git] / source3 / modules / vfs_gpfs.c
1 /*
2    Unix SMB/CIFS implementation.
3    Wrap gpfs calls in vfs functions.
4
5    Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
6
7    Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
8                             and Gomati Mohanan <gomati.mohanan@in.ibm.com>
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
29
30 #include <gpfs_gpl.h>
31 #include "nfs4_acls.h"
32 #include "vfs_gpfs.h"
33
34 struct gpfs_config_data {
35         bool sharemodes;
36         bool leases;
37 };
38
39
40 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, 
41                                  uint32 share_mode, uint32 access_mask)
42 {
43
44         struct gpfs_config_data *config;
45
46         SMB_VFS_HANDLE_GET_DATA(handle, config,
47                                 struct gpfs_config_data,
48                                 return -1);
49
50         START_PROFILE(syscall_kernel_flock);
51
52         kernel_flock(fsp->fh->fd, share_mode, access_mask);
53
54         if (config->sharemodes
55                 && !set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
56                 return -1;
57         }
58
59         END_PROFILE(syscall_kernel_flock);
60
61         return 0;
62 }
63
64 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
65 {
66
67         struct gpfs_config_data *config;
68
69         SMB_VFS_HANDLE_GET_DATA(handle, config,
70                                 struct gpfs_config_data,
71                                 return -1);
72
73         if (config->sharemodes && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
74                 set_gpfs_sharemode(fsp, 0, 0);
75         }
76
77         return SMB_VFS_NEXT_CLOSE(handle, fsp);
78 }
79
80 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, 
81                              int leasetype)
82 {
83         struct gpfs_config_data *config;
84         int ret=0;
85
86         SMB_VFS_HANDLE_GET_DATA(handle, config,
87                                 struct gpfs_config_data,
88                                 return -1);
89
90         START_PROFILE(syscall_linux_setlease);
91
92         if (linux_set_lease_sighandler(fsp->fh->fd) == -1)
93                 return -1;
94
95         if (config->leases) {
96                 ret = set_gpfs_lease(fsp->fh->fd,leasetype);
97         }
98
99         if (ret < 0) {
100                 /* This must have come from GPFS not being available */
101                 /* or some other error, hence call the default */
102                 ret = linux_setlease(fsp->fh->fd, leasetype);
103         }
104
105         END_PROFILE(syscall_linux_setlease);
106
107         return ret;
108 }
109
110 static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
111                                       const char *path,
112                                       const char *name,
113                                       TALLOC_CTX *mem_ctx,
114                                       char **found_name)
115 {
116         int result;
117         char *full_path;
118         char real_pathname[PATH_MAX+1];
119         int buflen;
120
121         full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
122         if (full_path == NULL) {
123                 errno = ENOMEM;
124                 return -1;
125         }
126
127         buflen = sizeof(real_pathname) - 1;
128
129         result = smbd_gpfs_get_realfilename_path(full_path, real_pathname,
130                                                  &buflen);
131
132         TALLOC_FREE(full_path);
133
134         if ((result == -1) && (errno == ENOSYS)) {
135                 return SMB_VFS_NEXT_GET_REAL_FILENAME(
136                         handle, path, name, mem_ctx, found_name);
137         }
138
139         if (result == -1) {
140                 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
141                            strerror(errno)));
142                 return -1;
143         }
144
145         /*
146          * GPFS does not necessarily null-terminate the returned path
147          * but instead returns the buffer length in buflen.
148          */
149
150         if (buflen < sizeof(real_pathname)) {
151                 real_pathname[buflen] = '\0';
152         } else {
153                 real_pathname[sizeof(real_pathname)-1] = '\0';
154         }
155
156         DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
157                    path, name, real_pathname));
158
159         name = strrchr_m(real_pathname, '/');
160         if (name == NULL) {
161                 errno = ENOENT;
162                 return -1;
163         }
164
165         *found_name = talloc_strdup(mem_ctx, name+1);
166         if (*found_name == NULL) {
167                 errno = ENOMEM;
168                 return -1;
169         }
170
171         return 0;
172 }
173
174 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
175 {
176         int     i;
177         if (gacl==NULL)
178         {
179                 DEBUG(0, ("gpfs acl is NULL\n"));
180                 return;
181         }
182
183         DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
184                 gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
185         for(i=0; i<gacl->acl_nace; i++)
186         {
187                 struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
188                 DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
189                         i, gace->aceType, gace->aceFlags, gace->aceMask,
190                         gace->aceIFlags, gace->aceWho));
191         }
192 }
193
194 static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
195 {
196         struct gpfs_acl *acl;
197         size_t len = 200;
198         int ret;
199         TALLOC_CTX *mem_ctx = talloc_tos();
200
201         acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
202         if (acl == NULL) {
203                 errno = ENOMEM;
204                 return NULL;
205         }
206
207         acl->acl_len = len;
208         acl->acl_level = 0;
209         acl->acl_version = 0;
210         acl->acl_type = type;
211
212         ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
213         if ((ret != 0) && (errno == ENOSPC)) {
214                 struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
215                         mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
216                 if (new_acl == NULL) {
217                         errno = ENOMEM;
218                         return NULL;
219                 }
220
221                 new_acl->acl_len = acl->acl_len;
222                 new_acl->acl_level = acl->acl_level;
223                 new_acl->acl_version = acl->acl_version;
224                 new_acl->acl_type = acl->acl_type;
225                 acl = new_acl;
226
227                 ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
228         }
229         if (ret != 0)
230         {
231                 DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
232                 return NULL;
233         }
234
235         return acl;
236 }
237
238 /* Tries to get nfs4 acls and returns SMB ACL allocated.
239  * On failure returns 1 if it got non-NFSv4 ACL to prompt 
240  * retry with POSIX ACL checks.
241  * On failure returns -1 if there is system (GPFS) error, check errno.
242  * Returns 0 on success
243  */
244 static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
245 {
246         int i;
247         struct gpfs_acl *gacl = NULL;
248         DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
249
250         /* First get the real acl length */
251         gacl = gpfs_getacl_alloc(fname, 0);
252         if (gacl == NULL) {
253                 DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
254                            fname, strerror(errno)));
255                 return -1;
256         }
257
258         if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
259                 DEBUG(10, ("Got non-nfsv4 acl\n"));
260                 /* Retry with POSIX ACLs check */
261                 return 1;
262         }
263
264         *ppacl = smb_create_smb4acl();
265
266         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
267                    gacl->acl_len, gacl->acl_level, gacl->acl_version,
268                    gacl->acl_nace));
269
270         for (i=0; i<gacl->acl_nace; i++) {
271                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
272                 SMB_ACE4PROP_T smbace;
273                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
274                            "who: %d\n", gace->aceType, gace->aceIFlags,
275                            gace->aceFlags, gace->aceMask, gace->aceWho));
276
277                 ZERO_STRUCT(smbace);
278                 if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
279                         smbace.flags |= SMB_ACE4_ID_SPECIAL;
280                         switch (gace->aceWho) {
281                         case ACE4_SPECIAL_OWNER:
282                                 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
283                                 break;
284                         case ACE4_SPECIAL_GROUP:
285                                 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
286                                 break;
287                         case ACE4_SPECIAL_EVERYONE:
288                                 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
289                                 break;
290                         default:
291                                 DEBUG(8, ("invalid special gpfs id %d "
292                                           "ignored\n", gace->aceWho));
293                                 continue; /* don't add it */
294                         }
295                 } else {
296                         if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
297                                 smbace.who.gid = gace->aceWho;
298                         else
299                                 smbace.who.uid = gace->aceWho;
300                 }
301
302                 /* remove redundent deny entries */
303                 if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
304                         struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
305                         if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
306                             prev->aceFlags == gace->aceFlags &&
307                             prev->aceIFlags == gace->aceIFlags &&
308                             (gace->aceMask & prev->aceMask) == 0 &&
309                             gace->aceWho == prev->aceWho) {
310                                 /* its redundent - skip it */
311                                 continue;
312                         }                                                
313                 }
314
315                 smbace.aceType = gace->aceType;
316                 smbace.aceFlags = gace->aceFlags;
317                 smbace.aceMask = gace->aceMask;
318                 smb_add_ace4(*ppacl, &smbace);
319         }
320
321         return 0;
322 }
323
324 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
325         files_struct *fsp, uint32 security_info,
326         struct security_descriptor **ppdesc)
327 {
328         SMB4ACL_T *pacl = NULL;
329         int     result;
330
331         *ppdesc = NULL;
332         result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
333
334         if (result == 0)
335                 return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
336
337         if (result > 0) {
338                 DEBUG(10, ("retrying with posix acl...\n"));
339                 return posix_fget_nt_acl(fsp, security_info, ppdesc);
340         }
341
342         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
343         return map_nt_error_from_unix(errno);
344 }
345
346 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
347         const char *name,
348         uint32 security_info, struct security_descriptor **ppdesc)
349 {
350         SMB4ACL_T *pacl = NULL;
351         int     result;
352
353         *ppdesc = NULL;
354         result = gpfs_get_nfs4_acl(name, &pacl);
355
356         if (result == 0)
357                 return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
358
359         if (result > 0) {
360                 DEBUG(10, ("retrying with posix acl...\n"));
361                 return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
362         }
363
364         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
365         return map_nt_error_from_unix(errno);
366 }
367
368 static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
369 {
370         int ret;
371         gpfs_aclLen_t gacl_len;
372         SMB4ACE_T       *smbace;
373         struct gpfs_acl *gacl;
374         TALLOC_CTX *mem_ctx  = talloc_tos();
375
376         gacl_len = sizeof(struct gpfs_acl) +
377                 (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
378
379         gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
380         if (gacl == NULL) {
381                 DEBUG(0, ("talloc failed\n"));
382                 errno = ENOMEM;
383                 return False;
384         }
385
386         gacl->acl_len = gacl_len;
387         gacl->acl_level = 0;
388         gacl->acl_version = GPFS_ACL_VERSION_NFS4;
389         gacl->acl_type = GPFS_ACL_TYPE_NFS4;
390         gacl->acl_nace = 0; /* change later... */
391
392         for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
393                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
394                 SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
395
396                 gace->aceType = aceprop->aceType;
397                 gace->aceFlags = aceprop->aceFlags;
398                 gace->aceMask = aceprop->aceMask;
399
400                 /*
401                  * GPFS can't distinguish between WRITE and APPEND on
402                  * files, so one being set without the other is an
403                  * error. Sorry for the many ()'s :-)
404                  */
405
406                 if (!fsp->is_directory
407                     &&
408                     ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
409                       && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
410                      ||
411                      (((gace->aceMask & ACE4_MASK_WRITE) != 0)
412                       && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
413                     &&
414                     lp_parm_bool(fsp->conn->params->service, "gpfs",
415                                  "merge_writeappend", True)) {
416                         DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
417                                   "WRITE^APPEND, setting WRITE|APPEND\n",
418                                   fsp_str_dbg(fsp)));
419                         gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
420                 }
421
422                 gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
423
424                 if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
425                 {
426                         switch(aceprop->who.special_id)
427                         {
428                         case SMB_ACE4_WHO_EVERYONE:
429                                 gace->aceWho = ACE4_SPECIAL_EVERYONE;
430                                 break;
431                         case SMB_ACE4_WHO_OWNER:
432                                 gace->aceWho = ACE4_SPECIAL_OWNER;
433                                 break;
434                         case SMB_ACE4_WHO_GROUP:
435                                 gace->aceWho = ACE4_SPECIAL_GROUP;
436                                 break;
437                         default:
438                                 DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
439                                 continue; /* don't add it !!! */
440                         }
441                 } else {
442                         /* just only for the type safety... */
443                         if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
444                                 gace->aceWho = aceprop->who.gid;
445                         else
446                                 gace->aceWho = aceprop->who.uid;
447                 }
448
449                 gacl->acl_nace++;
450         }
451
452         ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
453                                GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
454         if (ret != 0) {
455                 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
456                 gpfs_dumpacl(8, gacl);
457                 return False;
458         }
459
460         DEBUG(10, ("gpfs_putacl succeeded\n"));
461         return True;
462 }
463
464 static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
465 {
466         struct gpfs_acl *acl;
467         NTSTATUS result = NT_STATUS_ACCESS_DENIED;
468
469         acl = gpfs_getacl_alloc(fsp->fsp_name->base_name, 0);
470         if (acl == NULL)
471                 return result;
472
473         if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
474         {
475                 if (lp_parm_bool(fsp->conn->params->service, "gpfs",
476                                  "refuse_dacl_protected", false)
477                     && (psd->type&SEC_DESC_DACL_PROTECTED)) {
478                         DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
479                         return NT_STATUS_NOT_SUPPORTED;
480                 }
481
482                 result = smb_set_nt_acl_nfs4(
483                         fsp, security_info_sent, psd,
484                         gpfsacl_process_smbacl);
485         } else { /* assume POSIX ACL - by default... */
486                 result = set_nt_acl(fsp, security_info_sent, psd);
487         }
488
489         return result;
490 }
491
492 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
493 {
494         return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
495 }
496
497 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
498 {
499         SMB_ACL_T result;
500         int i;
501
502         result = sys_acl_init(pacl->acl_nace);
503         if (result == NULL) {
504                 errno = ENOMEM;
505                 return NULL;
506         }
507
508         result->count = pacl->acl_nace;
509
510         for (i=0; i<pacl->acl_nace; i++) {
511                 struct smb_acl_entry *ace = &result->acl[i];
512                 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
513
514                 DEBUG(10, ("Converting type %d id %lu perm %x\n",
515                            (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
516                            (int)g_ace->ace_perm));
517
518                 switch (g_ace->ace_type) {
519                 case GPFS_ACL_USER:
520                         ace->a_type = SMB_ACL_USER;
521                         ace->uid = (uid_t)g_ace->ace_who;
522                         break;
523                 case GPFS_ACL_USER_OBJ:
524                         ace->a_type = SMB_ACL_USER_OBJ;
525                         break;
526                 case GPFS_ACL_GROUP:
527                         ace->a_type = SMB_ACL_GROUP;
528                         ace->gid = (gid_t)g_ace->ace_who;
529                         break;
530                 case GPFS_ACL_GROUP_OBJ:
531                         ace->a_type = SMB_ACL_GROUP_OBJ;
532                         break;
533                 case GPFS_ACL_OTHER:
534                         ace->a_type = SMB_ACL_OTHER;
535                         break;
536                 case GPFS_ACL_MASK:
537                         ace->a_type = SMB_ACL_MASK;
538                         break;
539                 default:
540                         DEBUG(10, ("Got invalid ace_type: %d\n",
541                                    g_ace->ace_type));
542                         errno = EINVAL;
543                         SAFE_FREE(result);
544                         return NULL;
545                 }
546
547                 ace->a_perm = 0;
548                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
549                         SMB_ACL_READ : 0;
550                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
551                         SMB_ACL_WRITE : 0;
552                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
553                         SMB_ACL_EXECUTE : 0;
554
555                 DEBUGADD(10, ("Converted to %d perm %x\n",
556                               ace->a_type, ace->a_perm));
557         }
558
559         return result;
560 }
561
562 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
563 {
564         struct gpfs_acl *pacl;
565         SMB_ACL_T result = NULL;
566
567         pacl = gpfs_getacl_alloc(path, type);
568
569         if (pacl == NULL) {
570                 DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
571                            path, strerror(errno)));
572                 if (errno == 0) {
573                         errno = EINVAL;
574                 }
575                 goto done;
576         }
577
578         if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
579                 DEBUG(10, ("Got acl version %d, expected %d\n",
580                            pacl->acl_version, GPFS_ACL_VERSION_POSIX));
581                 errno = EINVAL;
582                 goto done;
583         }
584
585         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
586                    pacl->acl_len, pacl->acl_level, pacl->acl_version,
587                    pacl->acl_nace));
588
589         result = gpfs2smb_acl(pacl);
590         if (result == NULL) {
591                 goto done;
592         }
593
594  done:
595
596         if (errno != 0) {
597                 SAFE_FREE(result);
598         }
599         return result;  
600 }
601
602 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
603                                           const char *path_p,
604                                           SMB_ACL_TYPE_T type)
605 {
606         gpfs_aclType_t gpfs_type;
607
608         switch(type) {
609         case SMB_ACL_TYPE_ACCESS:
610                 gpfs_type = GPFS_ACL_TYPE_ACCESS;
611                 break;
612         case SMB_ACL_TYPE_DEFAULT:
613                 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
614                 break;
615         default:
616                 DEBUG(0, ("Got invalid type: %d\n", type));
617                 smb_panic("exiting");
618         }
619
620         return gpfsacl_get_posix_acl(path_p, gpfs_type);
621 }
622
623 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
624                                         files_struct *fsp)
625 {
626         return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
627                                      GPFS_ACL_TYPE_ACCESS);
628 }
629
630 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
631                                      SMB_ACL_TYPE_T type)
632 {
633         gpfs_aclLen_t len;
634         struct gpfs_acl *result;
635         int i;
636         union gpfs_ace_union
637         {
638                 gpfs_ace_v1_t  ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
639                 gpfs_ace_v4_t  ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4  */
640         };
641
642         DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
643
644         len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
645                 (pacl->count)*sizeof(gpfs_ace_v1_t);
646
647         result = (struct gpfs_acl *)SMB_MALLOC(len);
648         if (result == NULL) {
649                 errno = ENOMEM;
650                 return result;
651         }
652
653         result->acl_len = len;
654         result->acl_level = 0;
655         result->acl_version = GPFS_ACL_VERSION_POSIX;
656         result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
657                 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
658         result->acl_nace = pacl->count;
659
660         for (i=0; i<pacl->count; i++) {
661                 const struct smb_acl_entry *ace = &pacl->acl[i];
662                 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
663
664                 DEBUG(10, ("Converting type %d perm %x\n",
665                            (int)ace->a_type, (int)ace->a_perm));
666
667                 g_ace->ace_perm = 0;
668
669                 switch(ace->a_type) {
670                 case SMB_ACL_USER:
671                         g_ace->ace_type = GPFS_ACL_USER;
672                         g_ace->ace_who = (gpfs_uid_t)ace->uid;
673                         break;
674                 case SMB_ACL_USER_OBJ:
675                         g_ace->ace_type = GPFS_ACL_USER_OBJ;
676                         g_ace->ace_perm |= ACL_PERM_CONTROL;
677                         g_ace->ace_who = 0;
678                         break;
679                 case SMB_ACL_GROUP:
680                         g_ace->ace_type = GPFS_ACL_GROUP;
681                         g_ace->ace_who = (gpfs_uid_t)ace->gid;
682                         break;
683                 case SMB_ACL_GROUP_OBJ:
684                         g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
685                         g_ace->ace_who = 0;
686                         break;
687                 case SMB_ACL_MASK:
688                         g_ace->ace_type = GPFS_ACL_MASK;
689                         g_ace->ace_perm = 0x8f;
690                         g_ace->ace_who = 0;
691                         break;
692                 case SMB_ACL_OTHER:
693                         g_ace->ace_type = GPFS_ACL_OTHER;
694                         g_ace->ace_who = 0;
695                         break;
696                 default:
697                         DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
698                         errno = EINVAL;
699                         SAFE_FREE(result);
700                         return NULL;
701                 }
702
703                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
704                         ACL_PERM_READ : 0;
705                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
706                         ACL_PERM_WRITE : 0;
707                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
708                         ACL_PERM_EXECUTE : 0;
709
710                 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
711                               g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
712         }
713
714         return result;
715 }
716
717 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
718                                     const char *name,
719                                     SMB_ACL_TYPE_T type,
720                                     SMB_ACL_T theacl)
721 {
722         struct gpfs_acl *gpfs_acl;
723         int result;
724
725         gpfs_acl = smb2gpfs_acl(theacl, type);
726         if (gpfs_acl == NULL) {
727                 return -1;
728         }
729
730         result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
731
732         SAFE_FREE(gpfs_acl);
733         return result;
734 }
735
736 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
737                                   files_struct *fsp,
738                                   SMB_ACL_T theacl)
739 {
740         return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
741                                         SMB_ACL_TYPE_ACCESS, theacl);
742 }
743
744 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
745                                            const char *path)
746 {
747         errno = ENOTSUP;
748         return -1;
749 }
750
751 /*
752  * Assumed: mode bits are shiftable and standard
753  * Output: the new aceMask field for an smb nfs4 ace
754  */
755 static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
756 {
757         const uint32 posix_nfs4map[3] = {
758                 SMB_ACE4_EXECUTE, /* execute */
759                 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
760                 SMB_ACE4_READ_DATA /* read */
761         };
762         int     i;
763         uint32_t        posix_mask = 0x01;
764         uint32_t        posix_bit;
765         uint32_t        nfs4_bits;
766
767         for(i=0; i<3; i++) {
768                 nfs4_bits = posix_nfs4map[i];
769                 posix_bit = rwx & posix_mask;
770
771                 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
772                         if (posix_bit)
773                                 aceMask |= nfs4_bits;
774                         else
775                                 aceMask &= ~nfs4_bits;
776                 } else {
777                         /* add deny bits when suitable */
778                         if (!posix_bit)
779                                 aceMask |= nfs4_bits;
780                         else
781                                 aceMask &= ~nfs4_bits;
782                 } /* other ace types are unexpected */
783
784                 posix_mask <<= 1;
785         }
786
787         return aceMask;
788 }
789
790 static int gpfsacl_emu_chmod(const char *path, mode_t mode)
791 {
792         SMB4ACL_T *pacl = NULL;
793         int     result;
794         bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
795         int     i;
796         files_struct    fake_fsp; /* TODO: rationalize parametrization */
797         SMB4ACE_T       *smbace;
798         NTSTATUS status;
799
800         DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
801
802         result = gpfs_get_nfs4_acl(path, &pacl);
803         if (result)
804                 return result;
805
806         if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
807                 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
808         }
809
810         for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
811                 SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
812                 uint32_t        specid = ace->who.special_id;
813
814                 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
815                     ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
816                     specid <= SMB_ACE4_WHO_EVERYONE) {
817
818                         uint32_t newMask;
819
820                         if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
821                                 haveAllowEntry[specid] = True;
822
823                         /* mode >> 6 for @owner, mode >> 3 for @group,
824                          * mode >> 0 for @everyone */
825                         newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
826                                                       mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
827                         if (ace->aceMask!=newMask) {
828                                 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
829                                            path, ace->aceMask, newMask, specid));
830                         }
831                         ace->aceMask = newMask;
832                 }
833         }
834
835         /* make sure we have at least ALLOW entries
836          * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
837          * - if necessary
838          */
839         for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
840                 SMB_ACE4PROP_T  ace;
841
842                 if (haveAllowEntry[i]==True)
843                         continue;
844
845                 ZERO_STRUCT(ace);
846                 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
847                 ace.flags |= SMB_ACE4_ID_SPECIAL;
848                 ace.who.special_id = i;
849
850                 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
851                         ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
852
853                 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
854                                                   mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
855
856                 /* don't add unnecessary aces */
857                 if (!ace.aceMask)
858                         continue;
859
860                 /* we add it to the END - as windows expects allow aces */
861                 smb_add_ace4(pacl, &ace);
862                 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
863                            path, mode, i, ace.aceMask));
864         }
865
866         /* don't add complementary DENY ACEs here */
867         ZERO_STRUCT(fake_fsp);
868         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
869                                             &fake_fsp.fsp_name);
870         if (!NT_STATUS_IS_OK(status)) {
871                 errno = map_errno_from_nt_status(status);
872                 return -1;
873         }
874         /* put the acl */
875         if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) {
876                 TALLOC_FREE(fake_fsp.fsp_name);
877                 return -1;
878         }
879
880         TALLOC_FREE(fake_fsp.fsp_name);
881         return 0; /* ok for [f]chmod */
882 }
883
884 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
885 {
886         struct smb_filename *smb_fname_cpath;
887         int rc;
888         NTSTATUS status;
889
890         status = create_synthetic_smb_fname(
891                 talloc_tos(), path, NULL, NULL, &smb_fname_cpath);
892
893         if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
894                 return -1;
895         }
896
897         /* avoid chmod() if possible, to preserve acls */
898         if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
899                 return 0;
900         }
901
902         rc = gpfsacl_emu_chmod(path, mode);
903         if (rc == 1)
904                 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
905         return rc;
906 }
907
908 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
909 {
910                  SMB_STRUCT_STAT st;
911                  int rc;
912
913                  if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
914                          return -1;
915                  }
916
917                  /* avoid chmod() if possible, to preserve acls */
918                  if ((st.st_ex_mode & ~S_IFMT) == mode) {
919                          return 0;
920                  }
921
922                  rc = gpfsacl_emu_chmod(fsp->fsp_name->base_name, mode);
923                  if (rc == 1)
924                          return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
925                  return rc;
926 }
927
928 static int gpfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
929                            const char *name, const void *value, size_t size,  int flags){
930         struct xattr_DOSATTRIB dosattrib;
931         enum ndr_err_code ndr_err;
932         DATA_BLOB blob;
933         const char *attrstr = value;
934         unsigned int dosmode=0;
935         struct gpfs_winattr attrs;
936         int ret = 0;
937
938         DEBUG(10, ("gpfs_set_xattr: %s \n",path));
939
940         /* Only handle DOS Attributes */
941         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
942                 DEBUG(1, ("gpfs_set_xattr:name is %s\n",name));
943                 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
944         }
945
946         blob.data = (uint8_t *)attrstr;
947         blob.length = size;
948
949         ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
950                         (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
951
952         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
953                 DEBUG(1, ("gpfs_set_xattr: bad ndr decode "
954                           "from EA on file %s: Error = %s\n",
955                           path, ndr_errstr(ndr_err)));
956                 return false;
957         }
958
959         if (dosattrib.version != 3) {
960                 DEBUG(1, ("gpfs_set_xattr: expected dosattrib version 3, got "
961                           "%d\n", (int)dosattrib.version));
962                 return false;
963         }
964         if (!(dosattrib.info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) {
965                 DEBUG(10, ("gpfs_set_xattr: XATTR_DOSINFO_ATTRIB not "
966                            "valid, ignoring\n"));
967                 return true;
968         }
969
970         dosmode = dosattrib.info.info3.attrib;
971
972         attrs.winAttrs = 0;
973         /*Just map RD_ONLY, ARCHIVE, SYSTEM HIDDEN and SPARSE. Ignore the others*/
974         if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
975                 attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
976         }
977         if (dosmode & FILE_ATTRIBUTE_HIDDEN){
978                         attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
979                 }
980         if (dosmode & FILE_ATTRIBUTE_SYSTEM){
981                         attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
982                 }
983         if (dosmode & FILE_ATTRIBUTE_READONLY){
984                         attrs.winAttrs |= GPFS_WINATTR_READONLY;
985         }
986         if (dosmode & FILE_ATTRIBUTE_SPARSE) {
987                 attrs.winAttrs |= GPFS_WINATTR_SPARSE_FILE;
988         }
989
990
991         ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
992                                 GPFS_WINATTR_SET_ATTRS, &attrs);
993         if ( ret == -1){
994                 DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
995                 return -1;
996         }
997
998         DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
999         return 0;
1000 }
1001
1002 static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle,  const char *path,
1003                               const char *name, void *value, size_t size){
1004         char *attrstr = value;
1005         unsigned int dosmode = 0;
1006         struct gpfs_winattr attrs;
1007         int ret = 0;
1008
1009         DEBUG(10, ("gpfs_get_xattr: %s \n",path));
1010
1011         /* Only handle DOS Attributes */
1012         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
1013                 DEBUG(1, ("gpfs_get_xattr:name is %s\n",name));
1014                 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
1015         }
1016
1017         ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1018         if ( ret == -1){
1019                 DEBUG(1, ("gpfs_get_xattr: Get GPFS attributes failed: %d\n",ret));
1020                 return -1;
1021         }
1022
1023         DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
1024
1025         /*Just map RD_ONLY, ARCHIVE, SYSTEM, HIDDEN and SPARSE. Ignore the others*/
1026         if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
1027                 dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1028         }
1029         if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
1030                 dosmode |= FILE_ATTRIBUTE_HIDDEN;
1031         }
1032         if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
1033                 dosmode |= FILE_ATTRIBUTE_SYSTEM;
1034         }
1035         if (attrs.winAttrs & GPFS_WINATTR_READONLY){
1036                 dosmode |= FILE_ATTRIBUTE_READONLY;
1037         }
1038         if (attrs.winAttrs & GPFS_WINATTR_SPARSE_FILE) {
1039                 dosmode |= FILE_ATTRIBUTE_SPARSE;
1040         }
1041
1042         snprintf(attrstr, size, "0x%2.2x", dosmode & SAMBA_ATTRIBUTES_MASK);
1043         DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
1044         return 4;
1045 }
1046
1047 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1048                          struct smb_filename *smb_fname)
1049 {
1050         struct gpfs_winattr attrs;
1051         char *fname = NULL;
1052         NTSTATUS status;
1053         int ret;
1054
1055         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1056         if (ret == -1) {
1057                 return -1;
1058         }
1059         status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
1060         if (!NT_STATUS_IS_OK(status)) {
1061                 errno = map_errno_from_nt_status(status);
1062                 return -1;
1063         }
1064         ret = get_gpfs_winattrs(CONST_DISCARD(char *, fname), &attrs);
1065         TALLOC_FREE(fname);
1066         if (ret == 0) {
1067                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1068                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1069         }
1070         return 0;
1071 }
1072
1073 static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
1074                           struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1075 {
1076         struct gpfs_winattr attrs;
1077         int ret;
1078
1079         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1080         if (ret == -1) {
1081                 return -1;
1082         }
1083         if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
1084                 return 0;
1085         }
1086         ret = smbd_fget_gpfs_winattrs(fsp->fh->fd, &attrs);
1087         if (ret == 0) {
1088                 sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1089                 sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1090         }
1091         return 0;
1092 }
1093
1094 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1095                           struct smb_filename *smb_fname)
1096 {
1097         struct gpfs_winattr attrs;
1098         char *path = NULL;
1099         NTSTATUS status;
1100         int ret;
1101
1102         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1103         if (ret == -1) {
1104                 return -1;
1105         }
1106         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1107         if (!NT_STATUS_IS_OK(status)) {
1108                 errno = map_errno_from_nt_status(status);
1109                 return -1;
1110         }
1111         ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1112         TALLOC_FREE(path);
1113         if (ret == 0) {
1114                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1115                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1116         }
1117         return 0;
1118 }
1119
1120 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
1121                         const struct smb_filename *smb_fname,
1122                         struct smb_file_time *ft)
1123 {
1124
1125         struct gpfs_winattr attrs;
1126         int ret;
1127         char *path = NULL;
1128         NTSTATUS status;
1129
1130         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1131         if(ret == -1){
1132                 DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed\n"));
1133                 return -1;
1134         }
1135
1136         if(null_timespec(ft->create_time)){
1137                 DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
1138                 return 0;
1139         }
1140
1141         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1142         if (!NT_STATUS_IS_OK(status)) {
1143                 errno = map_errno_from_nt_status(status);
1144                 return -1;
1145         }
1146
1147         attrs.winAttrs = 0;
1148         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1149         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1150
1151         ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
1152                                 GPFS_WINATTR_SET_CREATION_TIME, &attrs);
1153         if(ret == -1){
1154                 DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
1155                 return -1;
1156         }
1157         return 0;
1158
1159 }
1160
1161 static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
1162                                 SMB_OFF_T len)
1163 {
1164         int result;
1165
1166         result = smbd_gpfs_ftruncate(fsp->fh->fd, len);
1167         if ((result == -1) && (errno == ENOSYS)) {
1168                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1169         }
1170         return result;
1171 }
1172
1173 int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
1174                         const char *user)
1175 {
1176         struct gpfs_config_data *config;
1177         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1178
1179         if (ret < 0) {
1180                 return ret;
1181         }
1182
1183         config = talloc_zero(handle->conn, struct gpfs_config_data);
1184         if (!config) {
1185                 SMB_VFS_NEXT_DISCONNECT(handle);
1186                 DEBUG(0, ("talloc_zero() failed\n")); return -1;
1187         }
1188
1189         config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
1190                                         "sharemodes", true);
1191
1192         config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
1193                                         "leases", true);
1194
1195         SMB_VFS_HANDLE_SET_DATA(handle, config,
1196                                 NULL, struct syncops_config_data,
1197                                 return -1);
1198
1199         return 0;
1200 }
1201
1202
1203 static struct vfs_fn_pointers vfs_gpfs_fns = {
1204         .connect_fn = vfs_gpfs_connect,
1205         .kernel_flock = vfs_gpfs_kernel_flock,
1206         .linux_setlease = vfs_gpfs_setlease,
1207         .get_real_filename = vfs_gpfs_get_real_filename,
1208         .fget_nt_acl = gpfsacl_fget_nt_acl,
1209         .get_nt_acl = gpfsacl_get_nt_acl,
1210         .fset_nt_acl = gpfsacl_fset_nt_acl,
1211         .sys_acl_get_file = gpfsacl_sys_acl_get_file,
1212         .sys_acl_get_fd = gpfsacl_sys_acl_get_fd,
1213         .sys_acl_set_file = gpfsacl_sys_acl_set_file,
1214         .sys_acl_set_fd = gpfsacl_sys_acl_set_fd,
1215         .sys_acl_delete_def_file = gpfsacl_sys_acl_delete_def_file,
1216         .chmod = vfs_gpfs_chmod,
1217         .fchmod = vfs_gpfs_fchmod,
1218         .close_fn = vfs_gpfs_close,
1219         .setxattr = gpfs_set_xattr,
1220         .getxattr = gpfs_get_xattr,
1221         .stat = vfs_gpfs_stat,
1222         .fstat = vfs_gpfs_fstat,
1223         .lstat = vfs_gpfs_lstat,
1224         .ntimes = vfs_gpfs_ntimes,
1225         .ftruncate = vfs_gpfs_ftruncate
1226 };
1227
1228 NTSTATUS vfs_gpfs_init(void);
1229 NTSTATUS vfs_gpfs_init(void)
1230 {
1231         init_gpfs();
1232
1233         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
1234                                 &vfs_gpfs_fns);
1235 }