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