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