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