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