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