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