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