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