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