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