6a9d3d5b8464a3b2034811f01f4a57f769d539bd
[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
37 struct gpfs_config_data {
38         bool sharemodes;
39         bool leases;
40         bool hsm;
41         bool syncio;
42         bool winattr;
43         bool ftruncate;
44         bool getrealfilename;
45 };
46
47
48 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, 
49                                  uint32 share_mode, uint32 access_mask)
50 {
51
52         struct gpfs_config_data *config;
53
54         SMB_VFS_HANDLE_GET_DATA(handle, config,
55                                 struct gpfs_config_data,
56                                 return -1);
57
58         START_PROFILE(syscall_kernel_flock);
59
60         kernel_flock(fsp->fh->fd, share_mode, access_mask);
61
62         if (config->sharemodes
63                 && !set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
64                 return -1;
65         }
66
67         END_PROFILE(syscall_kernel_flock);
68
69         return 0;
70 }
71
72 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
73 {
74
75         struct gpfs_config_data *config;
76
77         SMB_VFS_HANDLE_GET_DATA(handle, config,
78                                 struct gpfs_config_data,
79                                 return -1);
80
81         if (config->sharemodes && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
82                 set_gpfs_sharemode(fsp, 0, 0);
83         }
84
85         return SMB_VFS_NEXT_CLOSE(handle, fsp);
86 }
87
88 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, 
89                              int leasetype)
90 {
91         struct gpfs_config_data *config;
92         int ret=0;
93
94         SMB_VFS_HANDLE_GET_DATA(handle, config,
95                                 struct gpfs_config_data,
96                                 return -1);
97
98         START_PROFILE(syscall_linux_setlease);
99
100         if (linux_set_lease_sighandler(fsp->fh->fd) == -1)
101                 return -1;
102
103         if (config->leases) {
104                 ret = set_gpfs_lease(fsp->fh->fd,leasetype);
105         }
106
107         if (ret < 0) {
108                 /* This must have come from GPFS not being available */
109                 /* or some other error, hence call the default */
110                 ret = linux_setlease(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 | GPFS_ACL_SAMBA, 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 | GPFS_ACL_SAMBA, 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
356         *ppdesc = NULL;
357         result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
358
359         if (result == 0)
360                 return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
361
362         if (result > 0) {
363                 DEBUG(10, ("retrying with posix acl...\n"));
364                 return posix_fget_nt_acl(fsp, security_info, ppdesc);
365         }
366
367         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
368         return map_nt_error_from_unix(errno);
369 }
370
371 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
372         const char *name,
373         uint32 security_info, struct security_descriptor **ppdesc)
374 {
375         SMB4ACL_T *pacl = NULL;
376         int     result;
377
378         *ppdesc = NULL;
379         result = gpfs_get_nfs4_acl(name, &pacl);
380
381         if (result == 0)
382                 return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
383
384         if (result > 0) {
385                 DEBUG(10, ("retrying with posix acl...\n"));
386                 return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
387         }
388
389         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
390         return map_nt_error_from_unix(errno);
391 }
392
393 static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
394 {
395         int ret;
396         gpfs_aclLen_t gacl_len;
397         SMB4ACE_T       *smbace;
398         struct gpfs_acl *gacl;
399         TALLOC_CTX *mem_ctx  = talloc_tos();
400
401         gacl_len = sizeof(struct gpfs_acl) +
402                 (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
403
404         gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
405         if (gacl == NULL) {
406                 DEBUG(0, ("talloc failed\n"));
407                 errno = ENOMEM;
408                 return False;
409         }
410
411         gacl->acl_len = gacl_len;
412         gacl->acl_level = 0;
413         gacl->acl_version = GPFS_ACL_VERSION_NFS4;
414         gacl->acl_type = GPFS_ACL_TYPE_NFS4;
415         gacl->acl_nace = 0; /* change later... */
416
417         for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
418                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
419                 SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
420
421                 gace->aceType = aceprop->aceType;
422                 gace->aceFlags = aceprop->aceFlags;
423                 gace->aceMask = aceprop->aceMask;
424
425                 /*
426                  * GPFS can't distinguish between WRITE and APPEND on
427                  * files, so one being set without the other is an
428                  * error. Sorry for the many ()'s :-)
429                  */
430
431                 if (!fsp->is_directory
432                     &&
433                     ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
434                       && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
435                      ||
436                      (((gace->aceMask & ACE4_MASK_WRITE) != 0)
437                       && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
438                     &&
439                     lp_parm_bool(fsp->conn->params->service, "gpfs",
440                                  "merge_writeappend", True)) {
441                         DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
442                                   "WRITE^APPEND, setting WRITE|APPEND\n",
443                                   fsp_str_dbg(fsp)));
444                         gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
445                 }
446
447                 gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
448
449                 if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
450                 {
451                         switch(aceprop->who.special_id)
452                         {
453                         case SMB_ACE4_WHO_EVERYONE:
454                                 gace->aceWho = ACE4_SPECIAL_EVERYONE;
455                                 break;
456                         case SMB_ACE4_WHO_OWNER:
457                                 gace->aceWho = ACE4_SPECIAL_OWNER;
458                                 break;
459                         case SMB_ACE4_WHO_GROUP:
460                                 gace->aceWho = ACE4_SPECIAL_GROUP;
461                                 break;
462                         default:
463                                 DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
464                                 continue; /* don't add it !!! */
465                         }
466                 } else {
467                         /* just only for the type safety... */
468                         if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
469                                 gace->aceWho = aceprop->who.gid;
470                         else
471                                 gace->aceWho = aceprop->who.uid;
472                 }
473
474                 gacl->acl_nace++;
475         }
476
477         ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
478                                GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
479         if (ret != 0) {
480                 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
481                 gpfs_dumpacl(8, gacl);
482                 return False;
483         }
484
485         DEBUG(10, ("gpfs_putacl succeeded\n"));
486         return True;
487 }
488
489 static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
490 {
491         struct gpfs_acl *acl;
492         NTSTATUS result = NT_STATUS_ACCESS_DENIED;
493
494         acl = gpfs_getacl_alloc(fsp->fsp_name->base_name, 0);
495         if (acl == NULL)
496                 return result;
497
498         if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
499         {
500                 if (lp_parm_bool(fsp->conn->params->service, "gpfs",
501                                  "refuse_dacl_protected", false)
502                     && (psd->type&SEC_DESC_DACL_PROTECTED)) {
503                         DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
504                         return NT_STATUS_NOT_SUPPORTED;
505                 }
506
507                 result = smb_set_nt_acl_nfs4(
508                         fsp, security_info_sent, psd,
509                         gpfsacl_process_smbacl);
510         } else { /* assume POSIX ACL - by default... */
511                 result = set_nt_acl(fsp, security_info_sent, psd);
512         }
513
514         return result;
515 }
516
517 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
518 {
519         return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
520 }
521
522 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
523 {
524         SMB_ACL_T result;
525         gpfs_aclCount_t i;
526
527         result = sys_acl_init(pacl->acl_nace);
528         if (result == NULL) {
529                 errno = ENOMEM;
530                 return NULL;
531         }
532
533         result->count = pacl->acl_nace;
534
535         for (i=0; i<pacl->acl_nace; i++) {
536                 struct smb_acl_entry *ace = &result->acl[i];
537                 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
538
539                 DEBUG(10, ("Converting type %d id %lu perm %x\n",
540                            (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
541                            (int)g_ace->ace_perm));
542
543                 switch (g_ace->ace_type) {
544                 case GPFS_ACL_USER:
545                         ace->a_type = SMB_ACL_USER;
546                         ace->uid = (uid_t)g_ace->ace_who;
547                         break;
548                 case GPFS_ACL_USER_OBJ:
549                         ace->a_type = SMB_ACL_USER_OBJ;
550                         break;
551                 case GPFS_ACL_GROUP:
552                         ace->a_type = SMB_ACL_GROUP;
553                         ace->gid = (gid_t)g_ace->ace_who;
554                         break;
555                 case GPFS_ACL_GROUP_OBJ:
556                         ace->a_type = SMB_ACL_GROUP_OBJ;
557                         break;
558                 case GPFS_ACL_OTHER:
559                         ace->a_type = SMB_ACL_OTHER;
560                         break;
561                 case GPFS_ACL_MASK:
562                         ace->a_type = SMB_ACL_MASK;
563                         break;
564                 default:
565                         DEBUG(10, ("Got invalid ace_type: %d\n",
566                                    g_ace->ace_type));
567                         errno = EINVAL;
568                         SAFE_FREE(result);
569                         return NULL;
570                 }
571
572                 ace->a_perm = 0;
573                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
574                         SMB_ACL_READ : 0;
575                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
576                         SMB_ACL_WRITE : 0;
577                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
578                         SMB_ACL_EXECUTE : 0;
579
580                 DEBUGADD(10, ("Converted to %d perm %x\n",
581                               ace->a_type, ace->a_perm));
582         }
583
584         return result;
585 }
586
587 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
588 {
589         struct gpfs_acl *pacl;
590         SMB_ACL_T result = NULL;
591
592         pacl = gpfs_getacl_alloc(path, type);
593
594         if (pacl == NULL) {
595                 DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
596                            path, strerror(errno)));
597                 if (errno == 0) {
598                         errno = EINVAL;
599                 }
600                 goto done;
601         }
602
603         if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
604                 DEBUG(10, ("Got acl version %d, expected %d\n",
605                            pacl->acl_version, GPFS_ACL_VERSION_POSIX));
606                 errno = EINVAL;
607                 goto done;
608         }
609
610         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
611                    pacl->acl_len, pacl->acl_level, pacl->acl_version,
612                    pacl->acl_nace));
613
614         result = gpfs2smb_acl(pacl);
615         if (result == NULL) {
616                 goto done;
617         }
618
619  done:
620
621         if (errno != 0) {
622                 SAFE_FREE(result);
623         }
624         return result;  
625 }
626
627 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
628                                           const char *path_p,
629                                           SMB_ACL_TYPE_T type)
630 {
631         gpfs_aclType_t gpfs_type;
632
633         switch(type) {
634         case SMB_ACL_TYPE_ACCESS:
635                 gpfs_type = GPFS_ACL_TYPE_ACCESS;
636                 break;
637         case SMB_ACL_TYPE_DEFAULT:
638                 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
639                 break;
640         default:
641                 DEBUG(0, ("Got invalid type: %d\n", type));
642                 smb_panic("exiting");
643         }
644
645         return gpfsacl_get_posix_acl(path_p, gpfs_type);
646 }
647
648 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
649                                         files_struct *fsp)
650 {
651         return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
652                                      GPFS_ACL_TYPE_ACCESS);
653 }
654
655 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
656                                      SMB_ACL_TYPE_T type)
657 {
658         gpfs_aclLen_t len;
659         struct gpfs_acl *result;
660         int i;
661         union gpfs_ace_union
662         {
663                 gpfs_ace_v1_t  ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
664                 gpfs_ace_v4_t  ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4  */
665         };
666
667         DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
668
669         len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
670                 (pacl->count)*sizeof(gpfs_ace_v1_t);
671
672         result = (struct gpfs_acl *)SMB_MALLOC(len);
673         if (result == NULL) {
674                 errno = ENOMEM;
675                 return result;
676         }
677
678         result->acl_len = len;
679         result->acl_level = 0;
680         result->acl_version = GPFS_ACL_VERSION_POSIX;
681         result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
682                 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
683         result->acl_nace = pacl->count;
684
685         for (i=0; i<pacl->count; i++) {
686                 const struct smb_acl_entry *ace = &pacl->acl[i];
687                 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
688
689                 DEBUG(10, ("Converting type %d perm %x\n",
690                            (int)ace->a_type, (int)ace->a_perm));
691
692                 g_ace->ace_perm = 0;
693
694                 switch(ace->a_type) {
695                 case SMB_ACL_USER:
696                         g_ace->ace_type = GPFS_ACL_USER;
697                         g_ace->ace_who = (gpfs_uid_t)ace->uid;
698                         break;
699                 case SMB_ACL_USER_OBJ:
700                         g_ace->ace_type = GPFS_ACL_USER_OBJ;
701                         g_ace->ace_perm |= ACL_PERM_CONTROL;
702                         g_ace->ace_who = 0;
703                         break;
704                 case SMB_ACL_GROUP:
705                         g_ace->ace_type = GPFS_ACL_GROUP;
706                         g_ace->ace_who = (gpfs_uid_t)ace->gid;
707                         break;
708                 case SMB_ACL_GROUP_OBJ:
709                         g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
710                         g_ace->ace_who = 0;
711                         break;
712                 case SMB_ACL_MASK:
713                         g_ace->ace_type = GPFS_ACL_MASK;
714                         g_ace->ace_perm = 0x8f;
715                         g_ace->ace_who = 0;
716                         break;
717                 case SMB_ACL_OTHER:
718                         g_ace->ace_type = GPFS_ACL_OTHER;
719                         g_ace->ace_who = 0;
720                         break;
721                 default:
722                         DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
723                         errno = EINVAL;
724                         SAFE_FREE(result);
725                         return NULL;
726                 }
727
728                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
729                         ACL_PERM_READ : 0;
730                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
731                         ACL_PERM_WRITE : 0;
732                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
733                         ACL_PERM_EXECUTE : 0;
734
735                 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
736                               g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
737         }
738
739         return result;
740 }
741
742 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
743                                     const char *name,
744                                     SMB_ACL_TYPE_T type,
745                                     SMB_ACL_T theacl)
746 {
747         struct gpfs_acl *gpfs_acl;
748         int result;
749
750         gpfs_acl = smb2gpfs_acl(theacl, type);
751         if (gpfs_acl == NULL) {
752                 return -1;
753         }
754
755         result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
756
757         SAFE_FREE(gpfs_acl);
758         return result;
759 }
760
761 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
762                                   files_struct *fsp,
763                                   SMB_ACL_T theacl)
764 {
765         return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
766                                         SMB_ACL_TYPE_ACCESS, theacl);
767 }
768
769 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
770                                            const char *path)
771 {
772         errno = ENOTSUP;
773         return -1;
774 }
775
776 /*
777  * Assumed: mode bits are shiftable and standard
778  * Output: the new aceMask field for an smb nfs4 ace
779  */
780 static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
781 {
782         const uint32 posix_nfs4map[3] = {
783                 SMB_ACE4_EXECUTE, /* execute */
784                 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
785                 SMB_ACE4_READ_DATA /* read */
786         };
787         int     i;
788         uint32_t        posix_mask = 0x01;
789         uint32_t        posix_bit;
790         uint32_t        nfs4_bits;
791
792         for(i=0; i<3; i++) {
793                 nfs4_bits = posix_nfs4map[i];
794                 posix_bit = rwx & posix_mask;
795
796                 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
797                         if (posix_bit)
798                                 aceMask |= nfs4_bits;
799                         else
800                                 aceMask &= ~nfs4_bits;
801                 } else {
802                         /* add deny bits when suitable */
803                         if (!posix_bit)
804                                 aceMask |= nfs4_bits;
805                         else
806                                 aceMask &= ~nfs4_bits;
807                 } /* other ace types are unexpected */
808
809                 posix_mask <<= 1;
810         }
811
812         return aceMask;
813 }
814
815 static int gpfsacl_emu_chmod(const char *path, mode_t mode)
816 {
817         SMB4ACL_T *pacl = NULL;
818         int     result;
819         bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
820         int     i;
821         files_struct    fake_fsp; /* TODO: rationalize parametrization */
822         SMB4ACE_T       *smbace;
823         NTSTATUS status;
824
825         DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
826
827         result = gpfs_get_nfs4_acl(path, &pacl);
828         if (result)
829                 return result;
830
831         if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
832                 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
833         }
834
835         for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
836                 SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
837                 uint32_t        specid = ace->who.special_id;
838
839                 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
840                     ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
841                     specid <= SMB_ACE4_WHO_EVERYONE) {
842
843                         uint32_t newMask;
844
845                         if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
846                                 haveAllowEntry[specid] = True;
847
848                         /* mode >> 6 for @owner, mode >> 3 for @group,
849                          * mode >> 0 for @everyone */
850                         newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
851                                                       mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
852                         if (ace->aceMask!=newMask) {
853                                 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
854                                            path, ace->aceMask, newMask, specid));
855                         }
856                         ace->aceMask = newMask;
857                 }
858         }
859
860         /* make sure we have at least ALLOW entries
861          * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
862          * - if necessary
863          */
864         for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
865                 SMB_ACE4PROP_T  ace;
866
867                 if (haveAllowEntry[i]==True)
868                         continue;
869
870                 ZERO_STRUCT(ace);
871                 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
872                 ace.flags |= SMB_ACE4_ID_SPECIAL;
873                 ace.who.special_id = i;
874
875                 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
876                         ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
877
878                 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
879                                                   mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
880
881                 /* don't add unnecessary aces */
882                 if (!ace.aceMask)
883                         continue;
884
885                 /* we add it to the END - as windows expects allow aces */
886                 smb_add_ace4(pacl, &ace);
887                 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
888                            path, mode, i, ace.aceMask));
889         }
890
891         /* don't add complementary DENY ACEs here */
892         ZERO_STRUCT(fake_fsp);
893         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
894                                             &fake_fsp.fsp_name);
895         if (!NT_STATUS_IS_OK(status)) {
896                 errno = map_errno_from_nt_status(status);
897                 return -1;
898         }
899         /* put the acl */
900         if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) {
901                 TALLOC_FREE(fake_fsp.fsp_name);
902                 return -1;
903         }
904
905         TALLOC_FREE(fake_fsp.fsp_name);
906         return 0; /* ok for [f]chmod */
907 }
908
909 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
910 {
911         struct smb_filename *smb_fname_cpath;
912         int rc;
913         NTSTATUS status;
914
915         status = create_synthetic_smb_fname(
916                 talloc_tos(), path, NULL, NULL, &smb_fname_cpath);
917
918         if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
919                 return -1;
920         }
921
922         /* avoid chmod() if possible, to preserve acls */
923         if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
924                 return 0;
925         }
926
927         rc = gpfsacl_emu_chmod(path, mode);
928         if (rc == 1)
929                 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
930         return rc;
931 }
932
933 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
934 {
935                  SMB_STRUCT_STAT st;
936                  int rc;
937
938                  if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
939                          return -1;
940                  }
941
942                  /* avoid chmod() if possible, to preserve acls */
943                  if ((st.st_ex_mode & ~S_IFMT) == mode) {
944                          return 0;
945                  }
946
947                  rc = gpfsacl_emu_chmod(fsp->fsp_name->base_name, mode);
948                  if (rc == 1)
949                          return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
950                  return rc;
951 }
952
953 static int gpfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
954                            const char *name, const void *value, size_t size,  int flags){
955         struct xattr_DOSATTRIB dosattrib;
956         enum ndr_err_code ndr_err;
957         DATA_BLOB blob;
958         const char *attrstr = value;
959         unsigned int dosmode=0;
960         struct gpfs_winattr attrs;
961         int ret = 0;
962         struct gpfs_config_data *config;
963
964         SMB_VFS_HANDLE_GET_DATA(handle, config,
965                                 struct gpfs_config_data,
966                                 return -1);
967
968         if (!config->winattr) {
969                 DEBUG(10, ("gpfs_set_xattr:name is %s -> next\n",name));
970                 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
971         }
972
973         DEBUG(10, ("gpfs_set_xattr: %s \n",path));
974
975         /* Only handle DOS Attributes */
976         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
977                 DEBUG(5, ("gpfs_set_xattr:name is %s\n",name));
978                 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
979         }
980
981         blob.data = (uint8_t *)attrstr;
982         blob.length = size;
983
984         ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
985                         (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
986
987         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
988                 DEBUG(1, ("gpfs_set_xattr: bad ndr decode "
989                           "from EA on file %s: Error = %s\n",
990                           path, ndr_errstr(ndr_err)));
991                 return false;
992         }
993
994         if (dosattrib.version != 3) {
995                 DEBUG(1, ("gpfs_set_xattr: expected dosattrib version 3, got "
996                           "%d\n", (int)dosattrib.version));
997                 return false;
998         }
999         if (!(dosattrib.info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) {
1000                 DEBUG(10, ("gpfs_set_xattr: XATTR_DOSINFO_ATTRIB not "
1001                            "valid, ignoring\n"));
1002                 return true;
1003         }
1004
1005         dosmode = dosattrib.info.info3.attrib;
1006
1007         attrs.winAttrs = 0;
1008         /*Just map RD_ONLY, ARCHIVE, SYSTEM HIDDEN and SPARSE. Ignore the others*/
1009         if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
1010                 attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
1011         }
1012         if (dosmode & FILE_ATTRIBUTE_HIDDEN){
1013                         attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
1014                 }
1015         if (dosmode & FILE_ATTRIBUTE_SYSTEM){
1016                         attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
1017                 }
1018         if (dosmode & FILE_ATTRIBUTE_READONLY){
1019                         attrs.winAttrs |= GPFS_WINATTR_READONLY;
1020         }
1021         if (dosmode & FILE_ATTRIBUTE_SPARSE) {
1022                 attrs.winAttrs |= GPFS_WINATTR_SPARSE_FILE;
1023         }
1024
1025
1026         ret = set_gpfs_winattrs(discard_const_p(char, path),
1027                                 GPFS_WINATTR_SET_ATTRS, &attrs);
1028         if ( ret == -1){
1029                 if (errno == ENOSYS) {
1030                         return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
1031                                                      size, flags);
1032                 }
1033
1034                 DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
1035                 return -1;
1036         }
1037
1038         DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
1039         return 0;
1040 }
1041
1042 static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle,  const char *path,
1043                               const char *name, void *value, size_t size){
1044         char *attrstr = value;
1045         unsigned int dosmode = 0;
1046         struct gpfs_winattr attrs;
1047         int ret = 0;
1048         struct gpfs_config_data *config;
1049
1050         SMB_VFS_HANDLE_GET_DATA(handle, config,
1051                                 struct gpfs_config_data,
1052                                 return -1);
1053
1054         if (!config->winattr) {
1055                 DEBUG(10, ("gpfs_get_xattr:name is %s -> next\n",name));
1056                 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
1057         }
1058
1059         DEBUG(10, ("gpfs_get_xattr: %s \n",path));
1060
1061         /* Only handle DOS Attributes */
1062         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
1063                 DEBUG(5, ("gpfs_get_xattr:name is %s\n",name));
1064                 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
1065         }
1066
1067         ret = get_gpfs_winattrs(discard_const_p(char, path), &attrs);
1068         if ( ret == -1){
1069                 if (errno == ENOSYS) {
1070                         return SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
1071                                                      size);
1072                 }
1073
1074                 DEBUG(1, ("gpfs_get_xattr: Get GPFS attributes failed: "
1075                           "%d (%s)\n", ret, strerror(errno)));
1076                 return -1;
1077         }
1078
1079         DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
1080
1081         /*Just map RD_ONLY, ARCHIVE, SYSTEM, HIDDEN and SPARSE. Ignore the others*/
1082         if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
1083                 dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1084         }
1085         if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
1086                 dosmode |= FILE_ATTRIBUTE_HIDDEN;
1087         }
1088         if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
1089                 dosmode |= FILE_ATTRIBUTE_SYSTEM;
1090         }
1091         if (attrs.winAttrs & GPFS_WINATTR_READONLY){
1092                 dosmode |= FILE_ATTRIBUTE_READONLY;
1093         }
1094         if (attrs.winAttrs & GPFS_WINATTR_SPARSE_FILE) {
1095                 dosmode |= FILE_ATTRIBUTE_SPARSE;
1096         }
1097
1098         snprintf(attrstr, size, "0x%2.2x",
1099                  (unsigned int)(dosmode & SAMBA_ATTRIBUTES_MASK));
1100         DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
1101         return 4;
1102 }
1103
1104 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1105                          struct smb_filename *smb_fname)
1106 {
1107         struct gpfs_winattr attrs;
1108         char *fname = NULL;
1109         NTSTATUS status;
1110         int ret;
1111         struct gpfs_config_data *config;
1112
1113         SMB_VFS_HANDLE_GET_DATA(handle, config,
1114                                 struct gpfs_config_data,
1115                                 return -1);
1116
1117         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1118         if (ret == -1) {
1119                 return -1;
1120         }
1121
1122         if (!config->winattr) {
1123                 return 0;
1124         }
1125
1126         status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
1127         if (!NT_STATUS_IS_OK(status)) {
1128                 errno = map_errno_from_nt_status(status);
1129                 return -1;
1130         }
1131         ret = get_gpfs_winattrs(discard_const_p(char, fname), &attrs);
1132         TALLOC_FREE(fname);
1133         if (ret == 0) {
1134                 smb_fname->st.st_ex_calculated_birthtime = false;
1135                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1136                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1137                 smb_fname->st.vfs_private = attrs.winAttrs;
1138         }
1139         return 0;
1140 }
1141
1142 static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
1143                           struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1144 {
1145         struct gpfs_winattr attrs;
1146         int ret;
1147         struct gpfs_config_data *config;
1148
1149         SMB_VFS_HANDLE_GET_DATA(handle, config,
1150                                 struct gpfs_config_data,
1151                                 return -1);
1152
1153         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1154         if (ret == -1) {
1155                 return -1;
1156         }
1157         if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
1158                 return 0;
1159         }
1160         if (!config->winattr) {
1161                 return 0;
1162         }
1163
1164         ret = smbd_fget_gpfs_winattrs(fsp->fh->fd, &attrs);
1165         if (ret == 0) {
1166                 sbuf->st_ex_calculated_birthtime = false;
1167                 sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1168                 sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1169         }
1170         return 0;
1171 }
1172
1173 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1174                           struct smb_filename *smb_fname)
1175 {
1176         struct gpfs_winattr attrs;
1177         char *path = NULL;
1178         NTSTATUS status;
1179         int ret;
1180         struct gpfs_config_data *config;
1181
1182         SMB_VFS_HANDLE_GET_DATA(handle, config,
1183                                 struct gpfs_config_data,
1184                                 return -1);
1185
1186         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1187         if (ret == -1) {
1188                 return -1;
1189         }
1190         if (!config->winattr) {
1191                 return 0;
1192         }
1193
1194         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1195         if (!NT_STATUS_IS_OK(status)) {
1196                 errno = map_errno_from_nt_status(status);
1197                 return -1;
1198         }
1199         ret = get_gpfs_winattrs(discard_const_p(char, path), &attrs);
1200         TALLOC_FREE(path);
1201         if (ret == 0) {
1202                 smb_fname->st.st_ex_calculated_birthtime = false;
1203                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1204                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1205                 smb_fname->st.vfs_private = attrs.winAttrs;
1206         }
1207         return 0;
1208 }
1209
1210 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
1211                         const struct smb_filename *smb_fname,
1212                         struct smb_file_time *ft)
1213 {
1214
1215         struct gpfs_winattr attrs;
1216         int ret;
1217         char *path = NULL;
1218         NTSTATUS status;
1219         struct gpfs_config_data *config;
1220
1221         SMB_VFS_HANDLE_GET_DATA(handle, config,
1222                                 struct gpfs_config_data,
1223                                 return -1);
1224
1225         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1226         if(ret == -1){
1227                 /* don't complain if access was denied */
1228                 if (errno != EPERM && errno != EACCES) {
1229                         DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed:"
1230                                  "%s", strerror(errno)));
1231                 }
1232                 return -1;
1233         }
1234
1235         if(null_timespec(ft->create_time)){
1236                 DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
1237                 return 0;
1238         }
1239
1240         if (!config->winattr) {
1241                 return 0;
1242         }
1243
1244         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1245         if (!NT_STATUS_IS_OK(status)) {
1246                 errno = map_errno_from_nt_status(status);
1247                 return -1;
1248         }
1249
1250         attrs.winAttrs = 0;
1251         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1252         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1253
1254         ret = set_gpfs_winattrs(discard_const_p(char, path),
1255                                 GPFS_WINATTR_SET_CREATION_TIME, &attrs);
1256         if(ret == -1 && errno != ENOSYS){
1257                 DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
1258                 return -1;
1259         }
1260         return 0;
1261
1262 }
1263
1264 static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
1265                                 SMB_OFF_T len)
1266 {
1267         int result;
1268         struct gpfs_config_data *config;
1269
1270         SMB_VFS_HANDLE_GET_DATA(handle, config,
1271                                 struct gpfs_config_data,
1272                                 return -1);
1273
1274         if (!config->ftruncate) {
1275                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1276         }
1277
1278         result = smbd_gpfs_ftruncate(fsp->fh->fd, len);
1279         if ((result == -1) && (errno == ENOSYS)) {
1280                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1281         }
1282         return result;
1283 }
1284
1285 static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
1286                                 const struct smb_filename *fname,
1287                                 SMB_STRUCT_STAT *sbuf)
1288 {
1289         struct gpfs_winattr attrs;
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         if (!config->winattr) {
1299                 return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
1300         }
1301
1302         status = get_full_smb_filename(talloc_tos(), fname, &path);
1303         if (!NT_STATUS_IS_OK(status)) {
1304                 errno = map_errno_from_nt_status(status);
1305                 return -1;
1306         }
1307
1308         if (VALID_STAT(*sbuf)) {
1309                 attrs.winAttrs = sbuf->vfs_private;
1310         } else {
1311                 int ret;
1312                 ret = get_gpfs_winattrs(path, &attrs);
1313
1314                 if (ret == -1) {
1315                         TALLOC_FREE(path);
1316                         return false;
1317                 }
1318         }
1319         if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
1320                 DEBUG(10, ("%s is offline\n", path));
1321                 TALLOC_FREE(path);
1322                 return true;
1323         }
1324         DEBUG(10, ("%s is online\n", path));
1325         TALLOC_FREE(path);
1326         return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
1327 }
1328
1329 static bool vfs_gpfs_aio_force(struct vfs_handle_struct *handle,
1330                                struct files_struct *fsp)
1331 {
1332         return vfs_gpfs_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st);
1333 }
1334
1335 static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd,
1336                                  files_struct *fsp, const DATA_BLOB *hdr,
1337                                  SMB_OFF_T offset, size_t n)
1338 {
1339         if ((fsp->fsp_name->st.vfs_private & GPFS_WINATTR_OFFLINE) != 0) {
1340                 errno = ENOSYS;
1341                 return -1;
1342         }
1343         return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
1344 }
1345
1346 int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
1347                         const char *user)
1348 {
1349         struct gpfs_config_data *config;
1350         int ret;
1351
1352         smbd_gpfs_lib_init();
1353
1354         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1355
1356         if (ret < 0) {
1357                 return ret;
1358         }
1359
1360         config = talloc_zero(handle->conn, struct gpfs_config_data);
1361         if (!config) {
1362                 SMB_VFS_NEXT_DISCONNECT(handle);
1363                 DEBUG(0, ("talloc_zero() failed\n"));
1364                 return -1;
1365         }
1366
1367         config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
1368                                         "sharemodes", true);
1369
1370         config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
1371                                         "leases", true);
1372
1373         config->hsm = lp_parm_bool(SNUM(handle->conn), "gpfs",
1374                                    "hsm", false);
1375
1376         config->syncio = lp_parm_bool(SNUM(handle->conn), "gpfs",
1377                                       "syncio", false);
1378
1379         config->winattr = lp_parm_bool(SNUM(handle->conn), "gpfs",
1380                                        "winattr", false);
1381
1382         config->ftruncate = lp_parm_bool(SNUM(handle->conn), "gpfs",
1383                                          "ftruncate", true);
1384
1385         config->getrealfilename = lp_parm_bool(SNUM(handle->conn), "gpfs",
1386                                                "getrealfilename", true);
1387
1388         SMB_VFS_HANDLE_SET_DATA(handle, config,
1389                                 NULL, struct gpfs_config_data,
1390                                 return -1);
1391
1392         return 0;
1393 }
1394
1395 static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
1396                                       enum timestamp_set_resolution *p_ts_res)
1397 {
1398         struct gpfs_config_data *config;
1399         uint32_t next;
1400
1401         next = SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res);
1402
1403         SMB_VFS_HANDLE_GET_DATA(handle, config,
1404                                 struct gpfs_config_data,
1405                                 return next);
1406
1407         if (config->hsm) {
1408                 next |= FILE_SUPPORTS_REMOTE_STORAGE;
1409         }
1410         return next;
1411 }
1412
1413 static int vfs_gpfs_open(struct vfs_handle_struct *handle,
1414                          struct smb_filename *smb_fname, files_struct *fsp,
1415                          int flags, mode_t mode)
1416 {
1417         struct gpfs_config_data *config;
1418
1419         SMB_VFS_HANDLE_GET_DATA(handle, config,
1420                                 struct gpfs_config_data,
1421                                 return -1);
1422
1423         if (config->syncio) {
1424                 flags |= O_SYNC;
1425         }
1426         return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1427 }
1428
1429
1430 static struct vfs_fn_pointers vfs_gpfs_fns = {
1431         .connect_fn = vfs_gpfs_connect,
1432         .fs_capabilities_fn = vfs_gpfs_capabilities,
1433         .kernel_flock_fn = vfs_gpfs_kernel_flock,
1434         .linux_setlease_fn = vfs_gpfs_setlease,
1435         .get_real_filename_fn = vfs_gpfs_get_real_filename,
1436         .fget_nt_acl_fn = gpfsacl_fget_nt_acl,
1437         .get_nt_acl_fn = gpfsacl_get_nt_acl,
1438         .fset_nt_acl_fn = gpfsacl_fset_nt_acl,
1439         .sys_acl_get_file_fn = gpfsacl_sys_acl_get_file,
1440         .sys_acl_get_fd_fn = gpfsacl_sys_acl_get_fd,
1441         .sys_acl_set_file_fn = gpfsacl_sys_acl_set_file,
1442         .sys_acl_set_fd_fn = gpfsacl_sys_acl_set_fd,
1443         .sys_acl_delete_def_file_fn = gpfsacl_sys_acl_delete_def_file,
1444         .chmod_fn = vfs_gpfs_chmod,
1445         .fchmod_fn = vfs_gpfs_fchmod,
1446         .close_fn = vfs_gpfs_close,
1447         .setxattr_fn = gpfs_set_xattr,
1448         .getxattr_fn = gpfs_get_xattr,
1449         .stat_fn = vfs_gpfs_stat,
1450         .fstat_fn = vfs_gpfs_fstat,
1451         .lstat_fn = vfs_gpfs_lstat,
1452         .ntimes_fn = vfs_gpfs_ntimes,
1453         .is_offline_fn = vfs_gpfs_is_offline,
1454         .aio_force_fn = vfs_gpfs_aio_force,
1455         .sendfile_fn = vfs_gpfs_sendfile,
1456         .open_fn = vfs_gpfs_open,
1457         .ftruncate_fn = vfs_gpfs_ftruncate
1458 };
1459
1460 NTSTATUS vfs_gpfs_init(void);
1461 NTSTATUS vfs_gpfs_init(void)
1462 {
1463         init_gpfs();
1464
1465         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
1466                                 &vfs_gpfs_fns);
1467 }