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