s3:vfs use gpfs_lib_init
[ddiss/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
36 struct gpfs_config_data {
37         bool sharemodes;
38         bool leases;
39         bool hsm;
40 };
41
42
43 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, 
44                                  uint32 share_mode, uint32 access_mask)
45 {
46
47         struct gpfs_config_data *config;
48
49         SMB_VFS_HANDLE_GET_DATA(handle, config,
50                                 struct gpfs_config_data,
51                                 return -1);
52
53         START_PROFILE(syscall_kernel_flock);
54
55         kernel_flock(fsp->fh->fd, share_mode, access_mask);
56
57         if (config->sharemodes
58                 && !set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) {
59                 return -1;
60         }
61
62         END_PROFILE(syscall_kernel_flock);
63
64         return 0;
65 }
66
67 static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp)
68 {
69
70         struct gpfs_config_data *config;
71
72         SMB_VFS_HANDLE_GET_DATA(handle, config,
73                                 struct gpfs_config_data,
74                                 return -1);
75
76         if (config->sharemodes && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
77                 set_gpfs_sharemode(fsp, 0, 0);
78         }
79
80         return SMB_VFS_NEXT_CLOSE(handle, fsp);
81 }
82
83 static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, 
84                              int leasetype)
85 {
86         struct gpfs_config_data *config;
87         int ret=0;
88
89         SMB_VFS_HANDLE_GET_DATA(handle, config,
90                                 struct gpfs_config_data,
91                                 return -1);
92
93         START_PROFILE(syscall_linux_setlease);
94
95         if (linux_set_lease_sighandler(fsp->fh->fd) == -1)
96                 return -1;
97
98         if (config->leases) {
99                 ret = set_gpfs_lease(fsp->fh->fd,leasetype);
100         }
101
102         if (ret < 0) {
103                 /* This must have come from GPFS not being available */
104                 /* or some other error, hence call the default */
105                 ret = linux_setlease(fsp->fh->fd, leasetype);
106         }
107
108         END_PROFILE(syscall_linux_setlease);
109
110         return ret;
111 }
112
113 static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
114                                       const char *path,
115                                       const char *name,
116                                       TALLOC_CTX *mem_ctx,
117                                       char **found_name)
118 {
119         int result;
120         char *full_path;
121         char real_pathname[PATH_MAX+1];
122         int buflen;
123         bool mangled;
124
125         mangled = mangle_is_mangled(name, handle->conn->params);
126         if (mangled) {
127                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
128                                                       mem_ctx, found_name);
129         }
130
131         full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
132         if (full_path == NULL) {
133                 errno = ENOMEM;
134                 return -1;
135         }
136
137         buflen = sizeof(real_pathname) - 1;
138
139         result = smbd_gpfs_get_realfilename_path(full_path, real_pathname,
140                                                  &buflen);
141
142         TALLOC_FREE(full_path);
143
144         if ((result == -1) && (errno == ENOSYS)) {
145                 return SMB_VFS_NEXT_GET_REAL_FILENAME(
146                         handle, path, name, mem_ctx, found_name);
147         }
148
149         if (result == -1) {
150                 DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n",
151                            strerror(errno)));
152                 return -1;
153         }
154
155         /*
156          * GPFS does not necessarily null-terminate the returned path
157          * but instead returns the buffer length in buflen.
158          */
159
160         if (buflen < sizeof(real_pathname)) {
161                 real_pathname[buflen] = '\0';
162         } else {
163                 real_pathname[sizeof(real_pathname)-1] = '\0';
164         }
165
166         DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n",
167                    path, name, real_pathname));
168
169         name = strrchr_m(real_pathname, '/');
170         if (name == NULL) {
171                 errno = ENOENT;
172                 return -1;
173         }
174
175         *found_name = talloc_strdup(mem_ctx, name+1);
176         if (*found_name == NULL) {
177                 errno = ENOMEM;
178                 return -1;
179         }
180
181         return 0;
182 }
183
184 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
185 {
186         int     i;
187         if (gacl==NULL)
188         {
189                 DEBUG(0, ("gpfs acl is NULL\n"));
190                 return;
191         }
192
193         DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
194                 gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
195         for(i=0; i<gacl->acl_nace; i++)
196         {
197                 struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
198                 DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
199                         i, gace->aceType, gace->aceFlags, gace->aceMask,
200                         gace->aceIFlags, gace->aceWho));
201         }
202 }
203
204 static struct gpfs_acl *gpfs_getacl_alloc(const char *fname, gpfs_aclType_t type)
205 {
206         struct gpfs_acl *acl;
207         size_t len = 200;
208         int ret;
209         TALLOC_CTX *mem_ctx = talloc_tos();
210
211         acl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, len);
212         if (acl == NULL) {
213                 errno = ENOMEM;
214                 return NULL;
215         }
216
217         acl->acl_len = len;
218         acl->acl_level = 0;
219         acl->acl_version = 0;
220         acl->acl_type = type;
221
222         ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
223         if ((ret != 0) && (errno == ENOSPC)) {
224                 struct gpfs_acl *new_acl = (struct gpfs_acl *)TALLOC_SIZE(
225                         mem_ctx, acl->acl_len + sizeof(struct gpfs_acl));
226                 if (new_acl == NULL) {
227                         errno = ENOMEM;
228                         return NULL;
229                 }
230
231                 new_acl->acl_len = acl->acl_len;
232                 new_acl->acl_level = acl->acl_level;
233                 new_acl->acl_version = acl->acl_version;
234                 new_acl->acl_type = acl->acl_type;
235                 acl = new_acl;
236
237                 ret = smbd_gpfs_getacl((char *)fname, GPFS_GETACL_STRUCT | GPFS_ACL_SAMBA, acl);
238         }
239         if (ret != 0)
240         {
241                 DEBUG(8, ("smbd_gpfs_getacl failed with %s\n",strerror(errno)));
242                 return NULL;
243         }
244
245         return acl;
246 }
247
248 /* Tries to get nfs4 acls and returns SMB ACL allocated.
249  * On failure returns 1 if it got non-NFSv4 ACL to prompt 
250  * retry with POSIX ACL checks.
251  * On failure returns -1 if there is system (GPFS) error, check errno.
252  * Returns 0 on success
253  */
254 static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
255 {
256         int i;
257         struct gpfs_acl *gacl = NULL;
258         DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
259
260         /* First get the real acl length */
261         gacl = gpfs_getacl_alloc(fname, 0);
262         if (gacl == NULL) {
263                 DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
264                            fname, strerror(errno)));
265                 return -1;
266         }
267
268         if (gacl->acl_type != GPFS_ACL_TYPE_NFS4) {
269                 DEBUG(10, ("Got non-nfsv4 acl\n"));
270                 /* Retry with POSIX ACLs check */
271                 return 1;
272         }
273
274         *ppacl = smb_create_smb4acl();
275
276         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
277                    gacl->acl_len, gacl->acl_level, gacl->acl_version,
278                    gacl->acl_nace));
279
280         for (i=0; i<gacl->acl_nace; i++) {
281                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
282                 SMB_ACE4PROP_T smbace;
283                 DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
284                            "who: %d\n", gace->aceType, gace->aceIFlags,
285                            gace->aceFlags, gace->aceMask, gace->aceWho));
286
287                 ZERO_STRUCT(smbace);
288                 if (gace->aceIFlags & ACE4_IFLAG_SPECIAL_ID) {
289                         smbace.flags |= SMB_ACE4_ID_SPECIAL;
290                         switch (gace->aceWho) {
291                         case ACE4_SPECIAL_OWNER:
292                                 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
293                                 break;
294                         case ACE4_SPECIAL_GROUP:
295                                 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
296                                 break;
297                         case ACE4_SPECIAL_EVERYONE:
298                                 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
299                                 break;
300                         default:
301                                 DEBUG(8, ("invalid special gpfs id %d "
302                                           "ignored\n", gace->aceWho));
303                                 continue; /* don't add it */
304                         }
305                 } else {
306                         if (gace->aceFlags & ACE4_FLAG_GROUP_ID)
307                                 smbace.who.gid = gace->aceWho;
308                         else
309                                 smbace.who.uid = gace->aceWho;
310                 }
311
312                 /* remove redundent deny entries */
313                 if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
314                         struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
315                         if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
316                             prev->aceFlags == gace->aceFlags &&
317                             prev->aceIFlags == gace->aceIFlags &&
318                             (gace->aceMask & prev->aceMask) == 0 &&
319                             gace->aceWho == prev->aceWho) {
320                                 /* its redundent - skip it */
321                                 continue;
322                         }                                                
323                 }
324
325                 smbace.aceType = gace->aceType;
326                 smbace.aceFlags = gace->aceFlags;
327                 smbace.aceMask = gace->aceMask;
328                 smb_add_ace4(*ppacl, &smbace);
329         }
330
331         return 0;
332 }
333
334 static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
335         files_struct *fsp, uint32 security_info,
336         struct security_descriptor **ppdesc)
337 {
338         SMB4ACL_T *pacl = NULL;
339         int     result;
340
341         *ppdesc = NULL;
342         result = gpfs_get_nfs4_acl(fsp->fsp_name->base_name, &pacl);
343
344         if (result == 0)
345                 return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
346
347         if (result > 0) {
348                 DEBUG(10, ("retrying with posix acl...\n"));
349                 return posix_fget_nt_acl(fsp, security_info, ppdesc);
350         }
351
352         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
353         return map_nt_error_from_unix(errno);
354 }
355
356 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
357         const char *name,
358         uint32 security_info, struct security_descriptor **ppdesc)
359 {
360         SMB4ACL_T *pacl = NULL;
361         int     result;
362
363         *ppdesc = NULL;
364         result = gpfs_get_nfs4_acl(name, &pacl);
365
366         if (result == 0)
367                 return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
368
369         if (result > 0) {
370                 DEBUG(10, ("retrying with posix acl...\n"));
371                 return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
372         }
373
374         /* GPFS ACL was not read, something wrong happened, error code is set in errno */
375         return map_nt_error_from_unix(errno);
376 }
377
378 static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
379 {
380         int ret;
381         gpfs_aclLen_t gacl_len;
382         SMB4ACE_T       *smbace;
383         struct gpfs_acl *gacl;
384         TALLOC_CTX *mem_ctx  = talloc_tos();
385
386         gacl_len = sizeof(struct gpfs_acl) +
387                 (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t);
388
389         gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
390         if (gacl == NULL) {
391                 DEBUG(0, ("talloc failed\n"));
392                 errno = ENOMEM;
393                 return False;
394         }
395
396         gacl->acl_len = gacl_len;
397         gacl->acl_level = 0;
398         gacl->acl_version = GPFS_ACL_VERSION_NFS4;
399         gacl->acl_type = GPFS_ACL_TYPE_NFS4;
400         gacl->acl_nace = 0; /* change later... */
401
402         for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
403                 struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
404                 SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
405
406                 gace->aceType = aceprop->aceType;
407                 gace->aceFlags = aceprop->aceFlags;
408                 gace->aceMask = aceprop->aceMask;
409
410                 /*
411                  * GPFS can't distinguish between WRITE and APPEND on
412                  * files, so one being set without the other is an
413                  * error. Sorry for the many ()'s :-)
414                  */
415
416                 if (!fsp->is_directory
417                     &&
418                     ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
419                       && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
420                      ||
421                      (((gace->aceMask & ACE4_MASK_WRITE) != 0)
422                       && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
423                     &&
424                     lp_parm_bool(fsp->conn->params->service, "gpfs",
425                                  "merge_writeappend", True)) {
426                         DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
427                                   "WRITE^APPEND, setting WRITE|APPEND\n",
428                                   fsp_str_dbg(fsp)));
429                         gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
430                 }
431
432                 gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
433
434                 if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
435                 {
436                         switch(aceprop->who.special_id)
437                         {
438                         case SMB_ACE4_WHO_EVERYONE:
439                                 gace->aceWho = ACE4_SPECIAL_EVERYONE;
440                                 break;
441                         case SMB_ACE4_WHO_OWNER:
442                                 gace->aceWho = ACE4_SPECIAL_OWNER;
443                                 break;
444                         case SMB_ACE4_WHO_GROUP:
445                                 gace->aceWho = ACE4_SPECIAL_GROUP;
446                                 break;
447                         default:
448                                 DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id));
449                                 continue; /* don't add it !!! */
450                         }
451                 } else {
452                         /* just only for the type safety... */
453                         if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
454                                 gace->aceWho = aceprop->who.gid;
455                         else
456                                 gace->aceWho = aceprop->who.uid;
457                 }
458
459                 gacl->acl_nace++;
460         }
461
462         ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
463                                GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
464         if (ret != 0) {
465                 DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
466                 gpfs_dumpacl(8, gacl);
467                 return False;
468         }
469
470         DEBUG(10, ("gpfs_putacl succeeded\n"));
471         return True;
472 }
473
474 static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
475 {
476         struct gpfs_acl *acl;
477         NTSTATUS result = NT_STATUS_ACCESS_DENIED;
478
479         acl = gpfs_getacl_alloc(fsp->fsp_name->base_name, 0);
480         if (acl == NULL)
481                 return result;
482
483         if (acl->acl_version&GPFS_ACL_VERSION_NFS4)
484         {
485                 if (lp_parm_bool(fsp->conn->params->service, "gpfs",
486                                  "refuse_dacl_protected", false)
487                     && (psd->type&SEC_DESC_DACL_PROTECTED)) {
488                         DEBUG(2, ("Rejecting unsupported ACL with DACL_PROTECTED bit set\n"));
489                         return NT_STATUS_NOT_SUPPORTED;
490                 }
491
492                 result = smb_set_nt_acl_nfs4(
493                         fsp, security_info_sent, psd,
494                         gpfsacl_process_smbacl);
495         } else { /* assume POSIX ACL - by default... */
496                 result = set_nt_acl(fsp, security_info_sent, psd);
497         }
498
499         return result;
500 }
501
502 static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
503 {
504         return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
505 }
506
507 static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl)
508 {
509         SMB_ACL_T result;
510         int i;
511
512         result = sys_acl_init(pacl->acl_nace);
513         if (result == NULL) {
514                 errno = ENOMEM;
515                 return NULL;
516         }
517
518         result->count = pacl->acl_nace;
519
520         for (i=0; i<pacl->acl_nace; i++) {
521                 struct smb_acl_entry *ace = &result->acl[i];
522                 const struct gpfs_ace_v1 *g_ace = &pacl->ace_v1[i];
523
524                 DEBUG(10, ("Converting type %d id %lu perm %x\n",
525                            (int)g_ace->ace_type, (unsigned long)g_ace->ace_who,
526                            (int)g_ace->ace_perm));
527
528                 switch (g_ace->ace_type) {
529                 case GPFS_ACL_USER:
530                         ace->a_type = SMB_ACL_USER;
531                         ace->uid = (uid_t)g_ace->ace_who;
532                         break;
533                 case GPFS_ACL_USER_OBJ:
534                         ace->a_type = SMB_ACL_USER_OBJ;
535                         break;
536                 case GPFS_ACL_GROUP:
537                         ace->a_type = SMB_ACL_GROUP;
538                         ace->gid = (gid_t)g_ace->ace_who;
539                         break;
540                 case GPFS_ACL_GROUP_OBJ:
541                         ace->a_type = SMB_ACL_GROUP_OBJ;
542                         break;
543                 case GPFS_ACL_OTHER:
544                         ace->a_type = SMB_ACL_OTHER;
545                         break;
546                 case GPFS_ACL_MASK:
547                         ace->a_type = SMB_ACL_MASK;
548                         break;
549                 default:
550                         DEBUG(10, ("Got invalid ace_type: %d\n",
551                                    g_ace->ace_type));
552                         errno = EINVAL;
553                         SAFE_FREE(result);
554                         return NULL;
555                 }
556
557                 ace->a_perm = 0;
558                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_READ) ?
559                         SMB_ACL_READ : 0;
560                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_WRITE) ?
561                         SMB_ACL_WRITE : 0;
562                 ace->a_perm |= (g_ace->ace_perm & ACL_PERM_EXECUTE) ?
563                         SMB_ACL_EXECUTE : 0;
564
565                 DEBUGADD(10, ("Converted to %d perm %x\n",
566                               ace->a_type, ace->a_perm));
567         }
568
569         return result;
570 }
571
572 static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type)
573 {
574         struct gpfs_acl *pacl;
575         SMB_ACL_T result = NULL;
576
577         pacl = gpfs_getacl_alloc(path, type);
578
579         if (pacl == NULL) {
580                 DEBUG(10, ("gpfs_getacl failed for %s with %s\n",
581                            path, strerror(errno)));
582                 if (errno == 0) {
583                         errno = EINVAL;
584                 }
585                 goto done;
586         }
587
588         if (pacl->acl_version != GPFS_ACL_VERSION_POSIX) {
589                 DEBUG(10, ("Got acl version %d, expected %d\n",
590                            pacl->acl_version, GPFS_ACL_VERSION_POSIX));
591                 errno = EINVAL;
592                 goto done;
593         }
594
595         DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
596                    pacl->acl_len, pacl->acl_level, pacl->acl_version,
597                    pacl->acl_nace));
598
599         result = gpfs2smb_acl(pacl);
600         if (result == NULL) {
601                 goto done;
602         }
603
604  done:
605
606         if (errno != 0) {
607                 SAFE_FREE(result);
608         }
609         return result;  
610 }
611
612 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
613                                           const char *path_p,
614                                           SMB_ACL_TYPE_T type)
615 {
616         gpfs_aclType_t gpfs_type;
617
618         switch(type) {
619         case SMB_ACL_TYPE_ACCESS:
620                 gpfs_type = GPFS_ACL_TYPE_ACCESS;
621                 break;
622         case SMB_ACL_TYPE_DEFAULT:
623                 gpfs_type = GPFS_ACL_TYPE_DEFAULT;
624                 break;
625         default:
626                 DEBUG(0, ("Got invalid type: %d\n", type));
627                 smb_panic("exiting");
628         }
629
630         return gpfsacl_get_posix_acl(path_p, gpfs_type);
631 }
632
633 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
634                                         files_struct *fsp)
635 {
636         return gpfsacl_get_posix_acl(fsp->fsp_name->base_name,
637                                      GPFS_ACL_TYPE_ACCESS);
638 }
639
640 static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
641                                      SMB_ACL_TYPE_T type)
642 {
643         gpfs_aclLen_t len;
644         struct gpfs_acl *result;
645         int i;
646         union gpfs_ace_union
647         {
648                 gpfs_ace_v1_t  ace_v1[1]; /* when GPFS_ACL_VERSION_POSIX */
649                 gpfs_ace_v4_t  ace_v4[1]; /* when GPFS_ACL_VERSION_NFS4  */
650         };
651
652         DEBUG(10, ("smb2gpfs_acl: Got ACL with %d entries\n", pacl->count));
653
654         len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) +
655                 (pacl->count)*sizeof(gpfs_ace_v1_t);
656
657         result = (struct gpfs_acl *)SMB_MALLOC(len);
658         if (result == NULL) {
659                 errno = ENOMEM;
660                 return result;
661         }
662
663         result->acl_len = len;
664         result->acl_level = 0;
665         result->acl_version = GPFS_ACL_VERSION_POSIX;
666         result->acl_type = (type == SMB_ACL_TYPE_DEFAULT) ?
667                 GPFS_ACL_TYPE_DEFAULT : GPFS_ACL_TYPE_ACCESS;
668         result->acl_nace = pacl->count;
669
670         for (i=0; i<pacl->count; i++) {
671                 const struct smb_acl_entry *ace = &pacl->acl[i];
672                 struct gpfs_ace_v1 *g_ace = &result->ace_v1[i];
673
674                 DEBUG(10, ("Converting type %d perm %x\n",
675                            (int)ace->a_type, (int)ace->a_perm));
676
677                 g_ace->ace_perm = 0;
678
679                 switch(ace->a_type) {
680                 case SMB_ACL_USER:
681                         g_ace->ace_type = GPFS_ACL_USER;
682                         g_ace->ace_who = (gpfs_uid_t)ace->uid;
683                         break;
684                 case SMB_ACL_USER_OBJ:
685                         g_ace->ace_type = GPFS_ACL_USER_OBJ;
686                         g_ace->ace_perm |= ACL_PERM_CONTROL;
687                         g_ace->ace_who = 0;
688                         break;
689                 case SMB_ACL_GROUP:
690                         g_ace->ace_type = GPFS_ACL_GROUP;
691                         g_ace->ace_who = (gpfs_uid_t)ace->gid;
692                         break;
693                 case SMB_ACL_GROUP_OBJ:
694                         g_ace->ace_type = GPFS_ACL_GROUP_OBJ;
695                         g_ace->ace_who = 0;
696                         break;
697                 case SMB_ACL_MASK:
698                         g_ace->ace_type = GPFS_ACL_MASK;
699                         g_ace->ace_perm = 0x8f;
700                         g_ace->ace_who = 0;
701                         break;
702                 case SMB_ACL_OTHER:
703                         g_ace->ace_type = GPFS_ACL_OTHER;
704                         g_ace->ace_who = 0;
705                         break;
706                 default:
707                         DEBUG(10, ("Got invalid ace_type: %d\n", ace->a_type));
708                         errno = EINVAL;
709                         SAFE_FREE(result);
710                         return NULL;
711                 }
712
713                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_READ) ?
714                         ACL_PERM_READ : 0;
715                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_WRITE) ?
716                         ACL_PERM_WRITE : 0;
717                 g_ace->ace_perm |= (ace->a_perm & SMB_ACL_EXECUTE) ?
718                         ACL_PERM_EXECUTE : 0;
719
720                 DEBUGADD(10, ("Converted to %d id %d perm %x\n",
721                               g_ace->ace_type, g_ace->ace_who, g_ace->ace_perm));
722         }
723
724         return result;
725 }
726
727 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
728                                     const char *name,
729                                     SMB_ACL_TYPE_T type,
730                                     SMB_ACL_T theacl)
731 {
732         struct gpfs_acl *gpfs_acl;
733         int result;
734
735         gpfs_acl = smb2gpfs_acl(theacl, type);
736         if (gpfs_acl == NULL) {
737                 return -1;
738         }
739
740         result = smbd_gpfs_putacl((char *)name, GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gpfs_acl);
741
742         SAFE_FREE(gpfs_acl);
743         return result;
744 }
745
746 static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
747                                   files_struct *fsp,
748                                   SMB_ACL_T theacl)
749 {
750         return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
751                                         SMB_ACL_TYPE_ACCESS, theacl);
752 }
753
754 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
755                                            const char *path)
756 {
757         errno = ENOTSUP;
758         return -1;
759 }
760
761 /*
762  * Assumed: mode bits are shiftable and standard
763  * Output: the new aceMask field for an smb nfs4 ace
764  */
765 static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
766 {
767         const uint32 posix_nfs4map[3] = {
768                 SMB_ACE4_EXECUTE, /* execute */
769                 SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
770                 SMB_ACE4_READ_DATA /* read */
771         };
772         int     i;
773         uint32_t        posix_mask = 0x01;
774         uint32_t        posix_bit;
775         uint32_t        nfs4_bits;
776
777         for(i=0; i<3; i++) {
778                 nfs4_bits = posix_nfs4map[i];
779                 posix_bit = rwx & posix_mask;
780
781                 if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
782                         if (posix_bit)
783                                 aceMask |= nfs4_bits;
784                         else
785                                 aceMask &= ~nfs4_bits;
786                 } else {
787                         /* add deny bits when suitable */
788                         if (!posix_bit)
789                                 aceMask |= nfs4_bits;
790                         else
791                                 aceMask &= ~nfs4_bits;
792                 } /* other ace types are unexpected */
793
794                 posix_mask <<= 1;
795         }
796
797         return aceMask;
798 }
799
800 static int gpfsacl_emu_chmod(const char *path, mode_t mode)
801 {
802         SMB4ACL_T *pacl = NULL;
803         int     result;
804         bool    haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
805         int     i;
806         files_struct    fake_fsp; /* TODO: rationalize parametrization */
807         SMB4ACE_T       *smbace;
808         NTSTATUS status;
809
810         DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
811
812         result = gpfs_get_nfs4_acl(path, &pacl);
813         if (result)
814                 return result;
815
816         if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
817                 DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
818         }
819
820         for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
821                 SMB_ACE4PROP_T  *ace = smb_get_ace4(smbace);
822                 uint32_t        specid = ace->who.special_id;
823
824                 if (ace->flags&SMB_ACE4_ID_SPECIAL &&
825                     ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
826                     specid <= SMB_ACE4_WHO_EVERYONE) {
827
828                         uint32_t newMask;
829
830                         if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
831                                 haveAllowEntry[specid] = True;
832
833                         /* mode >> 6 for @owner, mode >> 3 for @group,
834                          * mode >> 0 for @everyone */
835                         newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
836                                                       mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
837                         if (ace->aceMask!=newMask) {
838                                 DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
839                                            path, ace->aceMask, newMask, specid));
840                         }
841                         ace->aceMask = newMask;
842                 }
843         }
844
845         /* make sure we have at least ALLOW entries
846          * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
847          * - if necessary
848          */
849         for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
850                 SMB_ACE4PROP_T  ace;
851
852                 if (haveAllowEntry[i]==True)
853                         continue;
854
855                 ZERO_STRUCT(ace);
856                 ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
857                 ace.flags |= SMB_ACE4_ID_SPECIAL;
858                 ace.who.special_id = i;
859
860                 if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
861                         ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
862
863                 ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
864                                                   mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
865
866                 /* don't add unnecessary aces */
867                 if (!ace.aceMask)
868                         continue;
869
870                 /* we add it to the END - as windows expects allow aces */
871                 smb_add_ace4(pacl, &ace);
872                 DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
873                            path, mode, i, ace.aceMask));
874         }
875
876         /* don't add complementary DENY ACEs here */
877         ZERO_STRUCT(fake_fsp);
878         status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
879                                             &fake_fsp.fsp_name);
880         if (!NT_STATUS_IS_OK(status)) {
881                 errno = map_errno_from_nt_status(status);
882                 return -1;
883         }
884         /* put the acl */
885         if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) {
886                 TALLOC_FREE(fake_fsp.fsp_name);
887                 return -1;
888         }
889
890         TALLOC_FREE(fake_fsp.fsp_name);
891         return 0; /* ok for [f]chmod */
892 }
893
894 static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
895 {
896         struct smb_filename *smb_fname_cpath;
897         int rc;
898         NTSTATUS status;
899
900         status = create_synthetic_smb_fname(
901                 talloc_tos(), path, NULL, NULL, &smb_fname_cpath);
902
903         if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
904                 return -1;
905         }
906
907         /* avoid chmod() if possible, to preserve acls */
908         if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
909                 return 0;
910         }
911
912         rc = gpfsacl_emu_chmod(path, mode);
913         if (rc == 1)
914                 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
915         return rc;
916 }
917
918 static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
919 {
920                  SMB_STRUCT_STAT st;
921                  int rc;
922
923                  if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
924                          return -1;
925                  }
926
927                  /* avoid chmod() if possible, to preserve acls */
928                  if ((st.st_ex_mode & ~S_IFMT) == mode) {
929                          return 0;
930                  }
931
932                  rc = gpfsacl_emu_chmod(fsp->fsp_name->base_name, mode);
933                  if (rc == 1)
934                          return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
935                  return rc;
936 }
937
938 static int gpfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
939                            const char *name, const void *value, size_t size,  int flags){
940         struct xattr_DOSATTRIB dosattrib;
941         enum ndr_err_code ndr_err;
942         DATA_BLOB blob;
943         const char *attrstr = value;
944         unsigned int dosmode=0;
945         struct gpfs_winattr attrs;
946         int ret = 0;
947
948         DEBUG(10, ("gpfs_set_xattr: %s \n",path));
949
950         /* Only handle DOS Attributes */
951         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
952                 DEBUG(1, ("gpfs_set_xattr:name is %s\n",name));
953                 return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
954         }
955
956         blob.data = (uint8_t *)attrstr;
957         blob.length = size;
958
959         ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
960                         (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
961
962         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
963                 DEBUG(1, ("gpfs_set_xattr: bad ndr decode "
964                           "from EA on file %s: Error = %s\n",
965                           path, ndr_errstr(ndr_err)));
966                 return false;
967         }
968
969         if (dosattrib.version != 3) {
970                 DEBUG(1, ("gpfs_set_xattr: expected dosattrib version 3, got "
971                           "%d\n", (int)dosattrib.version));
972                 return false;
973         }
974         if (!(dosattrib.info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) {
975                 DEBUG(10, ("gpfs_set_xattr: XATTR_DOSINFO_ATTRIB not "
976                            "valid, ignoring\n"));
977                 return true;
978         }
979
980         dosmode = dosattrib.info.info3.attrib;
981
982         attrs.winAttrs = 0;
983         /*Just map RD_ONLY, ARCHIVE, SYSTEM HIDDEN and SPARSE. Ignore the others*/
984         if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
985                 attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
986         }
987         if (dosmode & FILE_ATTRIBUTE_HIDDEN){
988                         attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
989                 }
990         if (dosmode & FILE_ATTRIBUTE_SYSTEM){
991                         attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
992                 }
993         if (dosmode & FILE_ATTRIBUTE_READONLY){
994                         attrs.winAttrs |= GPFS_WINATTR_READONLY;
995         }
996         if (dosmode & FILE_ATTRIBUTE_SPARSE) {
997                 attrs.winAttrs |= GPFS_WINATTR_SPARSE_FILE;
998         }
999
1000
1001         ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
1002                                 GPFS_WINATTR_SET_ATTRS, &attrs);
1003         if ( ret == -1){
1004                 if (errno == ENOSYS) {
1005                         return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
1006                                                      size, flags);
1007                 }
1008
1009                 DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
1010                 return -1;
1011         }
1012
1013         DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
1014         return 0;
1015 }
1016
1017 static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle,  const char *path,
1018                               const char *name, void *value, size_t size){
1019         char *attrstr = value;
1020         unsigned int dosmode = 0;
1021         struct gpfs_winattr attrs;
1022         int ret = 0;
1023
1024         DEBUG(10, ("gpfs_get_xattr: %s \n",path));
1025
1026         /* Only handle DOS Attributes */
1027         if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
1028                 DEBUG(1, ("gpfs_get_xattr:name is %s\n",name));
1029                 return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
1030         }
1031
1032         ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1033         if ( ret == -1){
1034                 if (errno == ENOSYS) {
1035                         return SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
1036                                                      size);
1037                 }
1038
1039                 DEBUG(1, ("gpfs_get_xattr: Get GPFS attributes failed: "
1040                           "%d (%s)\n", ret, strerror(errno)));
1041                 return -1;
1042         }
1043
1044         DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
1045
1046         /*Just map RD_ONLY, ARCHIVE, SYSTEM, HIDDEN and SPARSE. Ignore the others*/
1047         if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
1048                 dosmode |= FILE_ATTRIBUTE_ARCHIVE;
1049         }
1050         if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
1051                 dosmode |= FILE_ATTRIBUTE_HIDDEN;
1052         }
1053         if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
1054                 dosmode |= FILE_ATTRIBUTE_SYSTEM;
1055         }
1056         if (attrs.winAttrs & GPFS_WINATTR_READONLY){
1057                 dosmode |= FILE_ATTRIBUTE_READONLY;
1058         }
1059         if (attrs.winAttrs & GPFS_WINATTR_SPARSE_FILE) {
1060                 dosmode |= FILE_ATTRIBUTE_SPARSE;
1061         }
1062
1063         snprintf(attrstr, size, "0x%2.2x",
1064                  (unsigned int)(dosmode & SAMBA_ATTRIBUTES_MASK));
1065         DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
1066         return 4;
1067 }
1068
1069 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
1070                          struct smb_filename *smb_fname)
1071 {
1072         struct gpfs_winattr attrs;
1073         char *fname = NULL;
1074         NTSTATUS status;
1075         int ret;
1076
1077         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1078         if (ret == -1) {
1079                 return -1;
1080         }
1081         status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
1082         if (!NT_STATUS_IS_OK(status)) {
1083                 errno = map_errno_from_nt_status(status);
1084                 return -1;
1085         }
1086         ret = get_gpfs_winattrs(CONST_DISCARD(char *, fname), &attrs);
1087         TALLOC_FREE(fname);
1088         if (ret == 0) {
1089                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1090                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1091         }
1092         return 0;
1093 }
1094
1095 static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
1096                           struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1097 {
1098         struct gpfs_winattr attrs;
1099         int ret;
1100
1101         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1102         if (ret == -1) {
1103                 return -1;
1104         }
1105         if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
1106                 return 0;
1107         }
1108         ret = smbd_fget_gpfs_winattrs(fsp->fh->fd, &attrs);
1109         if (ret == 0) {
1110                 sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1111                 sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1112         }
1113         return 0;
1114 }
1115
1116 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
1117                           struct smb_filename *smb_fname)
1118 {
1119         struct gpfs_winattr attrs;
1120         char *path = NULL;
1121         NTSTATUS status;
1122         int ret;
1123
1124         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1125         if (ret == -1) {
1126                 return -1;
1127         }
1128         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1129         if (!NT_STATUS_IS_OK(status)) {
1130                 errno = map_errno_from_nt_status(status);
1131                 return -1;
1132         }
1133         ret = get_gpfs_winattrs(CONST_DISCARD(char *, path), &attrs);
1134         TALLOC_FREE(path);
1135         if (ret == 0) {
1136                 smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
1137                 smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
1138         }
1139         return 0;
1140 }
1141
1142 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
1143                         const struct smb_filename *smb_fname,
1144                         struct smb_file_time *ft)
1145 {
1146
1147         struct gpfs_winattr attrs;
1148         int ret;
1149         char *path = NULL;
1150         NTSTATUS status;
1151
1152         ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1153         if(ret == -1){
1154                 DEBUG(1,("vfs_gpfs_ntimes: SMB_VFS_NEXT_NTIMES failed\n"));
1155                 return -1;
1156         }
1157
1158         if(null_timespec(ft->create_time)){
1159                 DEBUG(10,("vfs_gpfs_ntimes:Create Time is NULL\n"));
1160                 return 0;
1161         }
1162
1163         status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
1164         if (!NT_STATUS_IS_OK(status)) {
1165                 errno = map_errno_from_nt_status(status);
1166                 return -1;
1167         }
1168
1169         attrs.winAttrs = 0;
1170         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
1171         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
1172
1173         ret = set_gpfs_winattrs(CONST_DISCARD(char *, path),
1174                                 GPFS_WINATTR_SET_CREATION_TIME, &attrs);
1175         if(ret == -1 && errno != ENOSYS){
1176                 DEBUG(1,("vfs_gpfs_ntimes: set GPFS ntimes failed %d\n",ret));
1177                 return -1;
1178         }
1179         return 0;
1180
1181 }
1182
1183 static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
1184                                 SMB_OFF_T len)
1185 {
1186         int result;
1187
1188         result = smbd_gpfs_ftruncate(fsp->fh->fd, len);
1189         if ((result == -1) && (errno == ENOSYS)) {
1190                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
1191         }
1192         return result;
1193 }
1194
1195 static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
1196                                 const struct smb_filename *fname,
1197                                 SMB_STRUCT_STAT *sbuf)
1198 {
1199         struct gpfs_winattr attrs;
1200         char *path = NULL;
1201         NTSTATUS status;
1202         int ret;
1203
1204         status = get_full_smb_filename(talloc_tos(), fname, &path);
1205         if (!NT_STATUS_IS_OK(status)) {
1206                 errno = map_errno_from_nt_status(status);
1207                 return -1;
1208         }
1209         ret = get_gpfs_winattrs(path, &attrs);
1210
1211         if (ret == -1) {
1212                 TALLOC_FREE(path);
1213                 return false;
1214         }
1215         if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
1216                 DEBUG(10, ("%s is offline\n", path));
1217                 TALLOC_FREE(path);
1218                 return true;
1219         }
1220         DEBUG(10, ("%s is online\n", path));
1221         TALLOC_FREE(path);
1222         return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
1223 }
1224
1225 static bool vfs_gpfs_aio_force(struct vfs_handle_struct *handle,
1226                                struct files_struct *fsp)
1227 {
1228         return vfs_gpfs_is_offline(handle, fsp->fsp_name, &fsp->fsp_name->st);
1229 }
1230
1231 int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
1232                         const char *user)
1233 {
1234         struct gpfs_config_data *config;
1235
1236         smbd_gpfs_lib_init();
1237
1238         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1239
1240         if (ret < 0) {
1241                 return ret;
1242         }
1243
1244         config = talloc_zero(handle->conn, struct gpfs_config_data);
1245         if (!config) {
1246                 SMB_VFS_NEXT_DISCONNECT(handle);
1247                 DEBUG(0, ("talloc_zero() failed\n")); return -1;
1248         }
1249
1250         config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
1251                                         "sharemodes", true);
1252
1253         config->leases = lp_parm_bool(SNUM(handle->conn), "gpfs",
1254                                         "leases", true);
1255
1256         config->hsm = lp_parm_bool(SNUM(handle->conn), "gpfs",
1257                                    "hsm", false);
1258
1259         SMB_VFS_HANDLE_SET_DATA(handle, config,
1260                                 NULL, struct gpfs_config_data,
1261                                 return -1);
1262
1263         return 0;
1264 }
1265
1266 static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
1267                                       enum timestamp_set_resolution *p_ts_res)
1268 {
1269         struct gpfs_config_data *config;
1270         uint32_t next;
1271
1272         next = SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res);
1273
1274         SMB_VFS_HANDLE_GET_DATA(handle, config,
1275                                 struct gpfs_config_data,
1276                                 return next);
1277
1278         if (config->hsm) {
1279                 next |= FILE_SUPPORTS_REMOTE_STORAGE;
1280         }
1281         return next;
1282 }
1283
1284
1285 static struct vfs_fn_pointers vfs_gpfs_fns = {
1286         .connect_fn = vfs_gpfs_connect,
1287         .fs_capabilities = vfs_gpfs_capabilities,
1288         .kernel_flock = vfs_gpfs_kernel_flock,
1289         .linux_setlease = vfs_gpfs_setlease,
1290         .get_real_filename = vfs_gpfs_get_real_filename,
1291         .fget_nt_acl = gpfsacl_fget_nt_acl,
1292         .get_nt_acl = gpfsacl_get_nt_acl,
1293         .fset_nt_acl = gpfsacl_fset_nt_acl,
1294         .sys_acl_get_file = gpfsacl_sys_acl_get_file,
1295         .sys_acl_get_fd = gpfsacl_sys_acl_get_fd,
1296         .sys_acl_set_file = gpfsacl_sys_acl_set_file,
1297         .sys_acl_set_fd = gpfsacl_sys_acl_set_fd,
1298         .sys_acl_delete_def_file = gpfsacl_sys_acl_delete_def_file,
1299         .chmod = vfs_gpfs_chmod,
1300         .fchmod = vfs_gpfs_fchmod,
1301         .close_fn = vfs_gpfs_close,
1302         .setxattr = gpfs_set_xattr,
1303         .getxattr = gpfs_get_xattr,
1304         .stat = vfs_gpfs_stat,
1305         .fstat = vfs_gpfs_fstat,
1306         .lstat = vfs_gpfs_lstat,
1307         .ntimes = vfs_gpfs_ntimes,
1308         .is_offline = vfs_gpfs_is_offline,
1309         .aio_force = vfs_gpfs_aio_force,
1310         .ftruncate = vfs_gpfs_ftruncate
1311 };
1312
1313 NTSTATUS vfs_gpfs_init(void);
1314 NTSTATUS vfs_gpfs_init(void)
1315 {
1316         init_gpfs();
1317
1318         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs",
1319                                 &vfs_gpfs_fns);
1320 }