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