1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright (C) CohrotFS Inc., 2015
5    	 * Author: Daniel Gryniewicz <dang@cohortfs.com>
6    	 *
7    	 *
8    	 * This program is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License as published by the Free Software Foundation; either
11   	 * version 3 of the License, or (at your option) any later version.
12   	 *
13   	 * This program is distributed in the hope that it will be useful,
14   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   	 * Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public
19   	 * License along with this library; if not, write to the Free Software
20   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21   	 * 02110-1301 USA
22   	 *
23   	 * -------------
24   	 */
25   	
26   	/**
27   	 * @addtogroup FSAL
28   	 * @{
29   	 */
30   	
31   	/**
32   	 * @file fsal_helper.c
33   	 * @author Daniel Gryniewicz <dang@cohortfs.com>
34   	 * @brief FSAL helper for clients
35   	 */
36   	
37   	#include "config.h"
38   	
39   	#include <stdint.h>
40   	#include <stddef.h>
41   	#include <stdlib.h>
42   	#include <errno.h>
43   	#include <string.h>
44   	#include "log.h"
45   	#include "fsal.h"
46   	#include "nfs_convert.h"
47   	#include "nfs_exports.h"
48   	#include "nfs4_acls.h"
49   	#include "sal_data.h"
50   	#include "sal_functions.h"
51   	#include "FSAL/fsal_commonlib.h"
52   	#include "sal_functions.h"
53   	
54   	/**
55   	 * This is a global counter of files opened.
56   	 *
57   	 * This is preliminary expected to go away.  Problems with this method are that
58   	 * it overcounts file descriptors for FSALs that don't use them for open files,
59   	 * and, under the Lieb Rearchitecture, FSALs will be responsible for caching
60   	 * their own file descriptors, with interfaces for Cache_Inode to interrogate
61   	 * them as to usage or instruct them to close them.
62   	 */
63   	
64   	size_t open_fd_count;
65   	
66   	static bool fsal_not_in_group_list(gid_t gid)
67   	{
68   		const struct user_cred *creds = op_ctx->creds;
69   		int i;
70   	
71   		if (creds->caller_gid == gid) {
72   	
73   			LogDebug(COMPONENT_FSAL,
74   				 "User %u is has active group %u", creds->caller_uid,
75   				 gid);
76   			return false;
77   		}
78   		for (i = 0; i < creds->caller_glen; i++) {
79   			if (creds->caller_garray[i] == gid) {
80   				LogDebug(COMPONENT_FSAL,
81   					 "User %u is member of group %u",
82   					 creds->caller_uid, gid);
83   				return false;
84   			}
85   		}
86   	
87   		LogDebug(COMPONENT_FSAL,
88   			 "User %u IS NOT member of group %u", creds->caller_uid,
89   			 gid);
90   		return true;
91   	}
92   	
93   	/**
94   	 * @brief Check permissions on opening a file.
95   	 *
96   	 * @param[in]  obj               The file being opened
97   	 * @param[in]  openflags         The access reqested on opening the file
98   	 * @param[in]  exclusive_create  Indicates the file is being exclusive create
99   	 * @param[out] reason            Description of why the access failed.
100  	 *
101  	 * @returns Status of the permission check.
102  	 */
103  	static fsal_status_t check_open_permission(struct fsal_obj_handle *obj,
104  						   fsal_openflags_t openflags,
105  						   bool exclusive_create,
106  						   char **reason)
107  	{
108  		fsal_status_t status = {0, 0};
109  		fsal_accessflags_t access_mask = 0;
110  	
111  		if (openflags & FSAL_O_READ)
112  			access_mask |= FSAL_READ_ACCESS;
113  	
114  		if (openflags & FSAL_O_WRITE)
115  			access_mask |= FSAL_WRITE_ACCESS;
116  	
117  		/* Ask for owner_skip on exclusive create (we will be checking the
118  		 * verifier later, so this allows a replay of
119  		 * open("foo", O_RDWR | O_CREAT | O_EXCL, 0) to succeed).
120  		 */
121  		status = obj->obj_ops->test_access(obj, access_mask,
122  						  NULL, NULL, exclusive_create);
123  	
124  		if (!FSAL_IS_ERROR(status)) {
125  			*reason = "";
126  			return status;
127  		}
128  	
129  		/* If non-permission error, return it. */
130  		if (status.major != ERR_FSAL_PERM) {
131  			*reason = "fsal_access failed - ";
132  			return status;
133  		}
134  	
135  		/* If WRITE access is requested, return permission
136  		 * error
137  		 */
138  		if (openflags & FSAL_O_WRITE) {
139  			*reason = "fsal_access failed with WRITE_ACCESS - ";
140  			return status;
141  		}
142  	
143  		/* If just a permission error and file was opened read
144  		 * only, try execute permission.
145  		 *
146  		 * NOTE: We don't do anything special for exclusive create here, if an
147  		 *       exclusive create replay failed the above permission check, it
148  		 *       presumably is no longer exclusively the creator of the file
149  		 *       because somehow the owner changed.
150  		 *
151  		 */
152  		status = fsal_access(obj, FSAL_EXECUTE_ACCESS);
153  	
154  		if (!FSAL_IS_ERROR(status))
155  			*reason = "";
156  		else
157  			*reason = "fsal_access failed with EXECUTE_ACCESS - ";
158  	
159  		return status;
160  	}
161  	
162  	/**
163  	 * @brief Checks permissions on an entry for setattrs
164  	 *
165  	 * This function checks if the supplied credentials are sufficient to perform
166  	 * the required setattrs.
167  	 *
168  	 * @param[in] obj     The file to be checked
169  	 * @param[in] attr    Attributes to set
170  	 * @param[in] current Current attributes for object
171  	 *
172  	 * @return FSAL status
173  	 */
174  	static fsal_status_t fsal_check_setattr_perms(struct fsal_obj_handle *obj,
175  						      struct attrlist *attr,
176  						      struct attrlist *current)
177  	{
178  		fsal_status_t status = {0, 0};
179  		fsal_accessflags_t access_check = 0;
180  		bool not_owner;
181  		char *note = "";
182  		const struct user_cred *creds = op_ctx->creds;
183  	
184  		/* Shortcut, if current user is root, then we can just bail out with
185  		 * success. */
186  		if (op_ctx->fsal_export->exp_ops.is_superuser(op_ctx->fsal_export,
187  							      creds)) {
188  			note = " (Ok for root user)";
189  			goto out;
190  		}
191  	
192  		fsal_prepare_attrs(current,
193  				   op_ctx->fsal_export->exp_ops.fs_supported_attrs(
194  								op_ctx->fsal_export)
195  				   & (ATTRS_CREDS | ATTR_MODE | ATTR_ACL));
196  	
197  		status = obj->obj_ops->getattrs(obj, current);
198  	
199  		if (FSAL_IS_ERROR(status))
200  			return status;
201  	
202  		not_owner = (creds->caller_uid != current->owner);
203  	
204  		/* Only ownership change need to be checked for owner */
205  		if (FSAL_TEST_MASK(attr->valid_mask, ATTR_OWNER)) {
206  			/* non-root is only allowed to "take ownership of file" */
207  			if (attr->owner != creds->caller_uid) {
208  				status = fsalstat(ERR_FSAL_PERM, 0);
209  				note = " (new OWNER was not user)";
210  				goto out;
211  			}
212  	
213  			/* Owner of file will always be able to "change" the owner to
214  			 * himself. */
215  			if (not_owner) {
216  				access_check |=
217  				    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);
218  				LogDebug(COMPONENT_FSAL,
219  					    "Change OWNER requires FSAL_ACE_PERM_WRITE_OWNER");
220  			}
221  		}
222  		/* Check if we are changing the owner_group, if owner_group is passed,
223  		 * but is the current owner_group, then that will be considered a
224  		 * NO-OP and allowed IF the caller is the owner of the file.
225  		 */
226  		if (FSAL_TEST_MASK(attr->valid_mask, ATTR_GROUP) &&
227  		    (attr->group != current->group || not_owner)) {
228  			/* non-root is only allowed to change group_owner to a group
229  			 * user is a member of. */
230  			int not_in_group = fsal_not_in_group_list(attr->group);
231  	
232  			if (not_in_group) {
233  				status = fsalstat(ERR_FSAL_PERM, 0);
234  				note = " (user is not member of new GROUP)";
235  				goto out;
236  			}
237  			/* Owner is always allowed to change the group_owner of a file
238  			 * to a group they are a member of.
239  			 */
240  			if (not_owner) {
241  				access_check |=
242  				    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);
243  				LogDebug(COMPONENT_FSAL,
244  					    "Change GROUP requires FSAL_ACE_PERM_WRITE_OWNER");
245  			}
246  		}
247  	
248  		/* Any attribute after this is always changeable by the owner.
249  		 * And the above attributes have already been validated as a valid
250  		 * change for the file owner to make. Note that the owner may be
251  		 * setting ATTR_OWNER but at this point it MUST be to himself, and
252  		 * thus is no-op and does not need FSAL_ACE_PERM_WRITE_OWNER.
253  		 */
254  		if (!not_owner) {
255  			note = " (Ok for owner)";
256  			goto out;
257  		}
258  	
259  		if (FSAL_TEST_MASK(attr->valid_mask, ATTR_MODE)
260  		    || FSAL_TEST_MASK(attr->valid_mask, ATTR_ACL)) {
261  			/* Changing mode or ACL requires ACE4_WRITE_ACL */
262  			access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL);
263  			LogDebug(COMPONENT_FSAL,
264  				    "Change MODE or ACL requires FSAL_ACE_PERM_WRITE_ACL");
265  		}
266  	
267  		if (FSAL_TEST_MASK(attr->valid_mask, ATTR_SIZE)) {
268  			/* Changing size requires owner or write permission */
269  		  /** @todo: does FSAL_ACE_PERM_APPEND_DATA allow enlarging the file? */
270  			access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA);
271  			LogDebug(COMPONENT_FSAL,
272  				    "Change SIZE requires FSAL_ACE_PERM_WRITE_DATA");
273  		}
274  	
275  		/* Check if just setting atime and mtime to "now" */
276  		if ((FSAL_TEST_MASK(attr->valid_mask, ATTR_MTIME_SERVER)
277  		     || FSAL_TEST_MASK(attr->valid_mask, ATTR_ATIME_SERVER))
278  		    && !FSAL_TEST_MASK(attr->valid_mask, ATTR_MTIME)
279  		    && !FSAL_TEST_MASK(attr->valid_mask, ATTR_ATIME)) {
280  			/* If either atime and/or mtime are set to "now" then need only
281  			 * have write permission.
282  			 *
283  			 * Technically, client should not send atime updates, but if
284  			 * they really do, we'll let them to make the perm check a bit
285  			 * simpler. */
286  			access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA);
287  			LogDebug(COMPONENT_FSAL,
288  				    "Change ATIME and MTIME to NOW requires FSAL_ACE_PERM_WRITE_DATA");
289  		} else if (FSAL_TEST_MASK(attr->valid_mask, ATTR_MTIME_SERVER)
290  			   || FSAL_TEST_MASK(attr->valid_mask, ATTR_ATIME_SERVER)
291  			   || FSAL_TEST_MASK(attr->valid_mask, ATTR_MTIME)
292  			   || FSAL_TEST_MASK(attr->valid_mask, ATTR_ATIME)) {
293  			/* Any other changes to atime or mtime require owner, root, or
294  			 * ACES4_WRITE_ATTRIBUTES.
295  			 *
296  			 * NOTE: we explicity do NOT check for update of atime only to
297  			 * "now". Section 10.6 of both RFC 3530 and RFC 5661 document
298  			 * the reasons clients should not do atime updates.
299  			 */
300  			access_check |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);
301  			LogDebug(COMPONENT_FSAL,
302  				    "Change ATIME and/or MTIME requires FSAL_ACE_PERM_WRITE_ATTR");
303  		}
304  	
305  		if (isDebug(COMPONENT_FSAL) || isDebug(COMPONENT_NFS_V4_ACL)) {
306  			char *need_write_owner = "";
307  			char *need_write_acl = "";
308  			char *need_write_data = "";
309  			char *need_write_attr = "";
310  	
311  			if (access_check & FSAL_ACE_PERM_WRITE_OWNER)
312  				need_write_owner = " WRITE_OWNER";
313  	
314  			if (access_check & FSAL_ACE_PERM_WRITE_ACL)
315  				need_write_acl = " WRITE_ACL";
316  	
317  			if (access_check & FSAL_ACE_PERM_WRITE_DATA)
318  				need_write_data = " WRITE_DATA";
319  	
320  			if (access_check & FSAL_ACE_PERM_WRITE_ATTR)
321  				need_write_attr = " WRITE_ATTR";
322  	
323  			LogDebug(COMPONENT_FSAL,
324  				    "Requires %s%s%s%s", need_write_owner,
325  				    need_write_acl, need_write_data, need_write_attr);
326  		}
327  	
328  		if (current->acl) {
329  			status = obj->obj_ops->test_access(obj, access_check, NULL,
330  							  NULL, false);
331  			note = " (checked ACL)";
332  			goto out;
333  		}
334  	
335  		if (access_check != FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA)) {
336  			/* Without an ACL, this user is not allowed some operation */
337  			status = fsalstat(ERR_FSAL_PERM, 0);
338  			note = " (no ACL to check)";
339  			goto out;
340  		}
341  	
342  		status = obj->obj_ops->test_access(obj, FSAL_W_OK, NULL, NULL, false);
343  	
344  		note = " (checked mode)";
345  	
346  	 out:
347  	
348  		if (FSAL_IS_ERROR(status)) {
349  			/* Done with the current attrs, caller will not expect them. */
350  			fsal_release_attrs(current);
351  		}
352  	
353  		LogDebug(COMPONENT_FSAL,
354  			    "Access check returned %s%s", fsal_err_txt(status),
355  			    note);
356  	
357  		return status;
358  	}
359  	
360  	fsal_status_t open2_by_name(struct fsal_obj_handle *in_obj,
361  				    struct state_t *state,
362  				    fsal_openflags_t openflags,
363  				    enum fsal_create_mode createmode,
364  				    const char *name,
365  				    struct attrlist *attr,
366  				    fsal_verifier_t verifier,
367  				    struct fsal_obj_handle **obj,
368  				    struct attrlist *attrs_out)
369  	{
370  		fsal_status_t status = { 0, 0 };
371  		fsal_status_t close_status = { 0, 0 };
372  		bool caller_perm_check = false;
373  		char *reason;
374  	
375  		*obj = NULL;
376  	
377  		if (name == NULL)
378  			return fsalstat(ERR_FSAL_INVAL, 0);
379  	
380  		if (in_obj->type != DIRECTORY)
381  			return fsalstat(ERR_FSAL_INVAL, 0);
382  	
383  		if (strcmp(name, ".") == 0 ||
384  		    strcmp(name, "..") == 0) {
385  			/* Can't open "." or ".."... */
386  			return fsalstat(ERR_FSAL_ISDIR, 0);
387  		}
388  	
389  		/* Check directory permission for LOOKUP */
390  		status = fsal_access(in_obj, FSAL_EXECUTE_ACCESS);
391  		if (FSAL_IS_ERROR(status))
392  			return status;
393  	
394  		status = in_obj->obj_ops->open2(in_obj,
395  					       state,
396  					       openflags,
397  					       createmode,
398  					       name,
399  					       attr,
400  					       verifier,
401  					       obj,
402  					       attrs_out,
403  					       &caller_perm_check);
404  		if (FSAL_IS_ERROR(status)) {
405  			LogFullDebug(COMPONENT_FSAL,
406  				     "FSAL %d %s returned %s",
407  				     (int) op_ctx->ctx_export->export_id,
408  				     op_ctx->ctx_export->fullpath,
409  				     fsal_err_txt(status));
410  			return status;
411  		}
412  	
413  		if (!state) {
414  			(void) atomic_inc_size_t(&open_fd_count);
415  		}
416  	
417  		LogFullDebug(COMPONENT_FSAL,
418  			     "Created entry %p FSAL %s for %s",
419  			     *obj, (*obj)->fsal->name, name);
420  	
421  		if (!caller_perm_check)
422  			return status;
423  	
424  		/* Do a permission check on the just opened file. */
425  		status = check_open_permission(*obj, openflags,
426  					       createmode >= FSAL_EXCLUSIVE, &reason);
427  	
428  		if (!FSAL_IS_ERROR(status))
429  			return status;
430  	
431  		LogDebug(COMPONENT_FSAL,
432  			 "Closing file check_open_permission failed %s-%s",
433  			 reason, fsal_err_txt(status));
434  	
435  		if (state != NULL)
436  			close_status = (*obj)->obj_ops->close2(*obj, state);
437  		else
438  			close_status = fsal_close(*obj);
439  	
440  		if (FSAL_IS_ERROR(close_status)) {
441  			/* Just log but don't return this error (we want to
442  			 * preserve the error that got us here).
443  			 */
444  			LogDebug(COMPONENT_FSAL,
445  				 "FSAL close2 failed with %s",
446  				 fsal_err_txt(close_status));
447  		}
448  	
449  		return status;
450  	}
451  	
452  	/**
453  	 * @brief Set attributes on a file
454  	 *
455  	 * The new attributes are copied over @a attr on success.
456  	 *
457  	 * The caller is expected to invoke fsal_release_attrs to release any
458  	 * resources held by the set attributes. The FSAL layer MAY have added an
459  	 * inherited ACL.
460  	 *
461  	 * @param[in]     obj    File to set attributes on
462  	 * @param[in]     bypass Bypass share reservation checking
463  	 * @param[in]     state  Possible state associated with the entry
464  	 * @param[in,out] attr   Attributes to set
465  	 * @return FSAL status
466  	 */
467  	fsal_status_t fsal_setattr(struct fsal_obj_handle *obj, bool bypass,
468  				   struct state_t *state, struct attrlist *attr)
469  	{
470  		fsal_status_t status = { 0, 0 };
471  		const struct user_cred *creds = op_ctx->creds;
472  		struct attrlist current;
473  		bool is_superuser;
474  	
475  		if ((attr->valid_mask & (ATTR_SIZE | ATTR4_SPACE_RESERVED))
476  		     && (obj->type != REGULAR_FILE)) {
477  			LogWarn(COMPONENT_FSAL,
478  				"Attempt to truncate non-regular file: type=%d",
479  				obj->type);
480  			return fsalstat(ERR_FSAL_BADTYPE, 0);
481  		}
482  		if ((attr->valid_mask & (ATTR_SIZE | ATTR_MODE))) {
483  			if (state_deleg_conflict(obj, true)) {
484  				return fsalstat(ERR_FSAL_DELAY, 0);
485  			}
486  		}
487  	
488  		/* Is it allowed to change times ? */
489  		if (!op_ctx->fsal_export->exp_ops.fs_supports(op_ctx->fsal_export,
490  							      fso_cansettime) &&
491  		    (FSAL_TEST_MASK
492  		     (attr->valid_mask,
493  		      (ATTR_ATIME | ATTR_CREATION | ATTR_CTIME | ATTR_MTIME))))
494  			return fsalstat(ERR_FSAL_INVAL, 0);
495  	
496  		/* Do permission checks, which returns with the attributes for the
497  		 * object if the caller is not root.
498  		 */
499  		status = fsal_check_setattr_perms(obj, attr, &current);
500  	
501  		if (FSAL_IS_ERROR(status))
502  			return status;
503  	
504  		is_superuser = op_ctx->fsal_export->exp_ops.is_superuser(
505  						op_ctx->fsal_export, creds);
506  		/* Test for the following condition from chown(2):
507  		 *
508  		 *     When the owner or group of an executable file are changed by an
509  		 *     unprivileged user the S_ISUID and S_ISGID mode bits are cleared.
510  		 *     POSIX does not specify whether this also should happen when
511  		 *     root does the chown(); the Linux behavior depends on the kernel
512  		 *     version.  In case of a non-group-executable file (i.e., one for
513  		 *     which the S_IXGRP bit is not set) the S_ISGID bit indicates
514  		 *     mandatory locking, and is not cleared by a chown().
515  		 *
516  		 */
517  		if (!is_superuser &&
518  		    (FSAL_TEST_MASK(attr->valid_mask, ATTR_OWNER) ||
519  		     FSAL_TEST_MASK(attr->valid_mask, ATTR_GROUP)) &&
520  		    ((current.mode & (S_IXOTH | S_IXUSR | S_IXGRP)) != 0) &&
521  		    ((current.mode & (S_ISUID | S_ISGID)) != 0)) {
522  			/* Non-priviledged user changing ownership on an executable
523  			 * file with S_ISUID or S_ISGID bit set, need to be cleared.
524  			 */
525  			if (!FSAL_TEST_MASK(attr->valid_mask, ATTR_MODE)) {
526  				/* Mode wasn't being set, so set it now, start with
527  				 * the current attributes.
528  				 */
529  				attr->mode = current.mode;
530  				FSAL_SET_MASK(attr->valid_mask, ATTR_MODE);
531  			}
532  	
533  			/* Don't clear S_ISGID if the file isn't group executable.
534  			 * In that case, S_ISGID indicates mandatory locking and
535  			 * is not cleared by chown.
536  			 */
537  			if ((current.mode & S_IXGRP) != 0)
538  				attr->mode &= ~S_ISGID;
539  	
540  			/* Clear S_ISUID. */
541  			attr->mode &= ~S_ISUID;
542  		}
543  	
544  		/* Test for the following condition from chmod(2):
545  		 *
546  		 *     If the calling process is not privileged (Linux: does not have
547  		 *     the CAP_FSETID capability), and the group of the file does not
548  		 *     match the effective group ID of the process or one of its
549  		 *     supplementary group IDs, the S_ISGID bit will be turned off,
550  		 *     but this will not cause an error to be returned.
551  		 *
552  		 * We test the actual mode being set before testing for group
553  		 * membership since that is a bit more expensive.
554  		 */
555  		if (!is_superuser &&
556  		    FSAL_TEST_MASK(attr->valid_mask, ATTR_MODE) &&
557  		    (attr->mode & S_ISGID) != 0 &&
558  		    fsal_not_in_group_list(current.group)) {
559  			/* Clear S_ISGID */
560  			attr->mode &= ~S_ISGID;
561  		}
562  	
563  		status = obj->obj_ops->setattr2(obj, bypass, state, attr);
564  		if (FSAL_IS_ERROR(status)) {
565  			if (status.major == ERR_FSAL_STALE) {
566  				LogEvent(COMPONENT_FSAL,
567  					 "FSAL returned STALE from setattr2");
568  			}
569  			return status;
570  		}
571  	
572  		if (!is_superuser)  {
573  			/* Done with the current attrs */
574  			fsal_release_attrs(&current);
575  		}
576  	
577  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
578  	}
579  	
580  	/**
581  	 * @brief Read the contents of a symlink
582  	 *
583  	 * @param[in] obj	Symlink to read
584  	 * @param[out] link_content	Buffer to fill with link contents
585  	 * @return FSAL status
586  	 */
587  	fsal_status_t fsal_readlink(struct fsal_obj_handle *obj,
588  				    struct gsh_buffdesc *link_content)
589  	{
590  		if (obj->type != SYMBOLIC_LINK)
591  			return fsalstat(ERR_FSAL_BADTYPE, 0);
592  	
593  		/* Never refresh.  FSAL_MDCACHE will override for cached FSALs. */
594  		return obj->obj_ops->readlink(obj, link_content, false);
595  	}
596  	
597  	/**
598  	 *
599  	 * @brief Links a new name to a file
600  	 *
601  	 * This function hard links a new name to an existing file.
602  	 *
603  	 * @param[in]  obj      The file to which to add the new name.  Must
604  	 *                      not be a directory.
605  	 * @param[in]  dest_dir The directory in which to create the new name
606  	 * @param[in]  name     The new name to add to the file
607  	 *
608  	 * @return FSAL status
609  	 *                                  in destination.
610  	 */
611  	fsal_status_t fsal_link(struct fsal_obj_handle *obj,
612  				struct fsal_obj_handle *dest_dir,
613  				const char *name)
614  	{
615  		fsal_status_t status = { 0, 0 };
616  	
617  		/* The file to be hardlinked can't be a DIRECTORY */
618  		if (obj->type == DIRECTORY)
619  			return fsalstat(ERR_FSAL_BADTYPE, 0);
620  	
621  		/* Is the destination a directory? */
622  		if (dest_dir->type != DIRECTORY)
623  			return fsalstat(ERR_FSAL_NOTDIR, 0);
624  	
625  		/* Must be the same FS */
626  		if (obj->fs != dest_dir->fs)
627  			return fsalstat(ERR_FSAL_XDEV, 0);
628  	
629  		if (!op_ctx->fsal_export->exp_ops.fs_supports(
630  				op_ctx->fsal_export,
631  				fso_link_supports_permission_checks)) {
632  			status = fsal_access(dest_dir,
633  				FSAL_MODE_MASK_SET(FSAL_W_OK) |
634  				FSAL_MODE_MASK_SET(FSAL_X_OK) |
635  				FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_EXECUTE) |
636  				FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE));
637  	
638  			if (FSAL_IS_ERROR(status))
639  				return status;
640  		}
641  	
642  		if (state_deleg_conflict(obj, true)) {
643  			LogDebug(COMPONENT_FSAL, "Found an existing delegation for %s",
644  				  name);
645  			return fsalstat(ERR_FSAL_DELAY, 0);
646  		}
647  	
648  		/* Rather than performing a lookup first, just try to make the
649  		   link and return the FSAL's error if it fails. */
650  		status = obj->obj_ops->link(obj, dest_dir, name);
651  		return status;
652  	}
653  	
654  	/**
655  	 * @brief Look up a name in a directory
656  	 *
657  	 * @param[in]  parent  Handle for the parent directory to be managed.
658  	 * @param[in]  name    Name of the file that we are looking up.
659  	 * @param[out] obj     Found file
660  	 *
661  	 * @note On success, @a handle has been ref'd
662  	 *
663  	 * @return FSAL status
664  	 */
665  	
666  	fsal_status_t fsal_lookup(struct fsal_obj_handle *parent,
667  				  const char *name,
668  				  struct fsal_obj_handle **obj,
669  				  struct attrlist *attrs_out)
670  	{
671  		fsal_status_t fsal_status = { 0, 0 };
672  		fsal_accessflags_t access_mask =
673  		    (FSAL_MODE_MASK_SET(FSAL_X_OK) |
674  		     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_EXECUTE));
675  	
676  		*obj = NULL;
677  	
678  		if (parent->type != DIRECTORY) {
679  			*obj = NULL;
680  			return fsalstat(ERR_FSAL_NOTDIR, 0);
681  		}
682  	
683  		fsal_status = fsal_access(parent, access_mask);
684  		if (FSAL_IS_ERROR(fsal_status))
685  			return fsal_status;
686  	
687  		if (strcmp(name, ".") == 0) {
688  			parent->obj_ops->get_ref(parent);
689  			*obj = parent;
690  			return get_optional_attrs(*obj, attrs_out);
691  		} else if (strcmp(name, "..") == 0)
692  			return fsal_lookupp(parent, obj, attrs_out);
693  	
694  	
695  		return parent->obj_ops->lookup(parent, name, obj, attrs_out);
696  	}
697  	
698  	/**
699  	 * @brief Look up a directory's parent
700  	 *
701  	 * @param[in]  obj     File whose parent is to be obtained.
702  	 * @param[out] parent  Parent directory
703  	 *
704  	 * @return FSAL status
705  	 */
706  	fsal_status_t fsal_lookupp(struct fsal_obj_handle *obj,
707  				   struct fsal_obj_handle **parent,
708  				   struct attrlist *attrs_out)
709  	{
710  		*parent = NULL;
711  	
712  		/* Never even think of calling FSAL_lookup on root/.. */
713  	
714  		if (obj->type == DIRECTORY) {
715  			fsal_status_t status = {0, 0};
716  			struct fsal_obj_handle *root_obj = NULL;
717  	
718  			status = nfs_export_get_root_entry(op_ctx->ctx_export,
719  							   &root_obj);
720  	
721  			if (FSAL_IS_ERROR(status))
722  				return status;
723  	
724  			if (obj == root_obj) {
725  				/* This entry is the root of the current export, so if
726  				 * we get this far, return itself. Note that NFS v4
727  				 * LOOKUPP will not come here, it catches the root entry
728  				 * earlier.
729  				 */
730  				*parent = obj;
731  				if (attrs_out != NULL) {
732  					/* Need to return the attributes of the
733  					 * current object.
734  					 */
735  					return obj->obj_ops->getattrs(obj, attrs_out);
736  				} else {
737  					/* Success */
738  					return fsalstat(ERR_FSAL_NO_ERROR, 0);
739  				}
740  			} else {
741  				/* Return entry from nfs_export_get_root_entry */
742  				root_obj->obj_ops->put_ref(root_obj);
743  			}
744  		}
745  	
746  		return obj->obj_ops->lookup(obj, "..", parent, attrs_out);
747  	}
748  	
749  	/**
750  	 * @brief Set the create verifier
751  	 *
752  	 * This function sets the mtime/atime attributes according to the create
753  	 * verifier
754  	 *
755  	 * @param[in] sattr   attrlist to be managed.
756  	 * @param[in] verf_hi High long of verifier
757  	 * @param[in] verf_lo Low long of verifier
758  	 *
759  	 */
760  	void
761  	fsal_create_set_verifier(struct attrlist *sattr, uint32_t verf_hi,
762  				 uint32_t verf_lo)
763  	{
764  		sattr->atime.tv_sec = verf_hi;
765  		sattr->atime.tv_nsec = 0;
766  		FSAL_SET_MASK(sattr->valid_mask, ATTR_ATIME);
767  		sattr->mtime.tv_sec = verf_lo;
768  		sattr->mtime.tv_nsec = 0;
769  		FSAL_SET_MASK(sattr->valid_mask, ATTR_MTIME);
770  	}
771  	
772  	/**
773  	 * @brief Creates an object in a directory
774  	 *
775  	 * This function creates an entry in the FSAL.  If the @a name exists, the
776  	 * returned error is ERR_FSAL_EXIST, and @a obj is set if the existing object
777  	 * has the same type as the requested one.
778  	 *
779  	 * The caller is expected to set the mode. Any other specified attributes
780  	 * will also be set.
781  	 *
782  	 * The caller is expected to invoke fsal_release_attrs to release any
783  	 * resources held by the set attributes. The FSAL layer MAY have added an
784  	 * inherited ACL.
785  	 *
786  	 * @param[in]  parent       Parent directory
787  	 * @param[in]  name         Name of the object to create
788  	 * @param[in]  type         Type of the object to create
789  	 * @param[in]  attrs        Attributes to be used at file creation
790  	 * @param[in]  link_content Contents for symlink
791  	 * @param[out] obj          Created file
792  	 *
793  	 * @note On success, @a obj has been ref'd
794  	 *
795  	 * @return FSAL status
796  	 */
797  	
798  	fsal_status_t fsal_create(struct fsal_obj_handle *parent,
799  				  const char *name,
800  				  object_file_type_t type,
801  				  struct attrlist *attrs,
802  				  const char *link_content,
803  				  struct fsal_obj_handle **obj,
804  				  struct attrlist *attrs_out)
805  	{
806  		fsal_status_t status = { 0, 0 };
807  		attrmask_t orig_mask = attrs->valid_mask;
808  	
(1) Event cond_const: Condition "type != BLOCK_FILE", taking false branch. Now the value of "type" is equal to 3.
(2) Event cond_const: Condition "type != CHARACTER_FILE", taking false branch. Now the value of "type" is equal to 2.
(3) Event cond_const: Condition "type != DIRECTORY", taking false branch. Now the value of "type" is equal to 7.
(4) Event cond_const: Condition "type != FIFO_FILE", taking false branch. Now the value of "type" is equal to 6.
(5) Event cond_const: Condition "type != REGULAR_FILE", taking false branch. Now the value of "type" is equal to 1.
(6) Event cond_const: Condition "type != SOCKET_FILE", taking false branch. Now the value of "type" is equal to 5.
(7) Event cond_const: Condition "type != SYMBOLIC_LINK", taking false branch. Now the value of "type" is equal to 4.
Also see events: [between][dead_error_condition][dead_error_condition][dead_error_begin]
809  		if ((type != REGULAR_FILE) && (type != DIRECTORY)
810  		    && (type != SYMBOLIC_LINK) && (type != SOCKET_FILE)
811  		    && (type != FIFO_FILE) && (type != CHARACTER_FILE)
812  		    && (type != BLOCK_FILE)) {
813  			status = fsalstat(ERR_FSAL_BADTYPE, 0);
814  	
815  			LogFullDebug(COMPONENT_FSAL,
816  				     "create failed because of bad type");
817  			*obj = NULL;
818  			goto out;
819  		}
820  	
821  		/* For support_ex API, turn off owner and/or group attr
822  		 * if they are the same as the credentials.
823  		 */
824  		if ((attrs->valid_mask & ATTR_OWNER) &&
825  		    attrs->owner == op_ctx->creds->caller_uid)
826  			FSAL_UNSET_MASK(attrs->valid_mask, ATTR_OWNER);
827  	
828  		if ((attrs->valid_mask & ATTR_GROUP) &&
829  		    attrs->group == op_ctx->creds->caller_gid)
830  			FSAL_UNSET_MASK(attrs->valid_mask, ATTR_GROUP);
831  	
832  		/* Permission checking will be done by the FSAL operation. */
833  	
834  		/* Try to create it first */
835  	
(8) Event between: When switching on "type", the value of "type" must be between 1 and 7.
Also see events: [cond_const][cond_const][cond_const][cond_const][cond_const][cond_const][cond_const][dead_error_condition][dead_error_condition][dead_error_begin]
836  		switch (type) {
837  		case REGULAR_FILE:
838  			status = fsal_open2(parent, NULL, FSAL_O_RDWR, FSAL_UNCHECKED,
839  					    name, attrs, NULL, obj, attrs_out);
840  			if (FSAL_IS_SUCCESS(status)) {
841  				/* Close it again; this is just a create */
842  				(void)fsal_close(*obj);
843  			}
844  			break;
845  	
846  		case DIRECTORY:
847  			status = parent->obj_ops->mkdir(parent, name, attrs,
848  						       obj, attrs_out);
849  			break;
850  	
851  		case SYMBOLIC_LINK:
852  			status = parent->obj_ops->symlink(parent, name, link_content,
853  							 attrs, obj, attrs_out);
854  			break;
855  	
856  		case SOCKET_FILE:
857  		case FIFO_FILE:
858  		case BLOCK_FILE:
859  		case CHARACTER_FILE:
860  			status = parent->obj_ops->mknode(parent, name, type,
861  							attrs, obj, attrs_out);
862  			break;
863  	
(9) Event dead_error_condition: The "switch" governing value "type" cannot be "NO_FILE_TYPE".
Also see events: [cond_const][cond_const][cond_const][cond_const][cond_const][cond_const][cond_const][between][dead_error_condition][dead_error_begin]
864  		case NO_FILE_TYPE:
(10) Event dead_error_condition: The "switch" governing value "type" cannot be "EXTENDED_ATTR".
(11) Event dead_error_begin: Execution cannot reach this statement: "case EXTENDED_ATTR:".
Also see events: [cond_const][cond_const][cond_const][cond_const][cond_const][cond_const][cond_const][between][dead_error_condition]
865  		case EXTENDED_ATTR:
866  			/* we should never go there */
867  			status = fsalstat(ERR_FSAL_BADTYPE, 0);
868  			*obj = NULL;
869  			LogFullDebug(COMPONENT_FSAL,
870  				     "create failed because inconsistent entry");
871  			goto out;
872  		}
873  	
874  		/* Check for the result */
875  		if (FSAL_IS_ERROR(status)) {
876  			if (status.major == ERR_FSAL_STALE) {
877  				LogEvent(COMPONENT_FSAL,
878  					 "FSAL returned STALE on create type %d", type);
879  			} else if (status.major == ERR_FSAL_EXIST) {
880  				/* Already exists. Check if type if correct */
881  				status = fsal_lookup(parent, name, obj, attrs_out);
882  				if (*obj != NULL) {
883  					status = fsalstat(ERR_FSAL_EXIST, 0);
884  					LogFullDebug(COMPONENT_FSAL,
885  						     "create failed because it already exists");
886  					if ((*obj)->type != type) {
887  						/* Incompatible types, returns NULL */
888  						(*obj)->obj_ops->put_ref((*obj));
889  						*obj = NULL;
890  						goto out;
891  					}
892  					if ((type == REGULAR_FILE) &&
893  					    (attrs->valid_mask & ATTR_SIZE) &&
894  					    attrs->filesize == 0) {
895  						attrs->valid_mask &= ATTR_SIZE;
896  						goto out;
897  					}
898  				}
899  			} else {
900  				*obj = NULL;
901  			}
902  			goto out;
903  		}
904  	
905  	 out:
906  	
907  		/* Restore original mask so caller isn't bamboozled... */
908  		attrs->valid_mask = orig_mask;
909  	
910  		LogFullDebug(COMPONENT_FSAL,
911  			     "Returning obj=%p status=%s for %s FSAL=%s", *obj,
912  			     fsal_err_txt(status), name, parent->fsal->name);
913  	
914  		return status;
915  	}
916  	
917  	/**
918  	 * @brief Return true if create verifier matches
919  	 *
920  	 * This function returns true if the create verifier matches
921  	 *
922  	 * @param[in] obj     File to be managed.
923  	 * @param[in] verf_hi High long of verifier
924  	 * @param[in] verf_lo Low long of verifier
925  	 *
926  	 * @return true if verified, false otherwise
927  	 *
928  	 */
929  	bool fsal_create_verify(struct fsal_obj_handle *obj, uint32_t verf_hi,
930  				uint32_t verf_lo)
931  	{
932  		/* True if the verifier matches */
933  		bool verified = false;
934  		struct attrlist attrs;
935  	
936  		fsal_prepare_attrs(&attrs, ATTR_ATIME | ATTR_MTIME);
937  	
938  		obj->obj_ops->getattrs(obj, &attrs);
939  		if (FSAL_TEST_MASK(attrs.valid_mask, ATTR_ATIME)
940  		    && FSAL_TEST_MASK(attrs.valid_mask, ATTR_MTIME)
941  		    && attrs.atime.tv_sec == verf_hi
942  		    && attrs.mtime.tv_sec == verf_lo)
943  			verified = true;
944  	
945  		/* Done with the attrs */
946  		fsal_release_attrs(&attrs);
947  	
948  		return verified;
949  	}
950  	
951  	struct fsal_populate_cb_state {
952  		struct fsal_obj_handle *directory;
953  		fsal_status_t *status;
954  		helper_readdir_cb cb;
955  		fsal_cookie_t last_cookie;
956  		enum cb_state cb_state;
957  		unsigned int *cb_nfound;
958  		attrmask_t attrmask;
959  		struct fsal_readdir_cb_parms cb_parms;
960  	};
961  	
962  	static enum fsal_dir_result
963  	populate_dirent(const char *name,
964  			struct fsal_obj_handle *obj,
965  			struct attrlist *attrs,
966  			void *dir_state,
967  			fsal_cookie_t cookie)
968  	{
969  		struct fsal_populate_cb_state *state =
970  		    (struct fsal_populate_cb_state *)dir_state;
971  		fsal_status_t status = {0, 0};
972  		enum fsal_dir_result retval;
973  	
974  		retval = DIR_CONTINUE;
975  		state->cb_parms.name = name;
976  	
977  		status.major = state->cb(&state->cb_parms, obj, attrs, attrs->fileid,
978  					 cookie, state->cb_state);
979  	
980  		if (status.major == ERR_FSAL_CROSS_JUNCTION) {
981  			struct fsal_obj_handle *junction_obj;
982  			struct gsh_export *junction_export = NULL;
983  			struct fsal_export *saved_export;
984  			struct attrlist attrs2;
985  	
986  			PTHREAD_RWLOCK_rdlock(&obj->state_hdl->state_lock);
987  	
988  			/* Get a reference to the junction_export and remember it
989  			 * only if the junction export is valid.
990  			 */
991  			if (obj->state_hdl->dir.junction_export != NULL &&
992  			    export_ready(obj->state_hdl->dir.junction_export)) {
993  				get_gsh_export_ref(obj->state_hdl->dir.junction_export);
994  				junction_export = obj->state_hdl->dir.junction_export;
995  			}
996  	
997  			PTHREAD_RWLOCK_unlock(&obj->state_hdl->state_lock);
998  	
999  			/* Get the root of the export across the junction. */
1000 			if (junction_export != NULL) {
1001 				status = nfs_export_get_root_entry(junction_export,
1002 								   &junction_obj);
1003 	
1004 				if (FSAL_IS_ERROR(status)) {
1005 					LogMajor(COMPONENT_FSAL,
1006 						 "Failed to get root for %s, id=%d, status = %s",
1007 						 junction_export->fullpath,
1008 						 junction_export->export_id,
1009 						 fsal_err_txt(status));
1010 					/* Need to signal problem to callback */
1011 					state->cb_state = CB_PROBLEM;
1012 					(void) state->cb(&state->cb_parms, NULL, NULL,
1013 							 0, cookie, state->cb_state);
1014 					/* Protocol layers NEVER do readahead. */
1015 					retval = DIR_TERMINATE;
1016 					put_gsh_export(junction_export);
1017 					goto out;
1018 				}
1019 			} else {
1020 				LogMajor(COMPONENT_FSAL,
1021 					 "A junction became stale");
1022 				/* Need to signal problem to callback */
1023 				state->cb_state = CB_PROBLEM;
1024 				(void) state->cb(&state->cb_parms, NULL, NULL, 0,
1025 						 cookie, state->cb_state);
1026 				/* Protocol layers NEVER do readahead. */
1027 				retval = DIR_TERMINATE;
1028 				goto out;
1029 			}
1030 	
1031 			/* Now we need to get the cross-junction attributes. */
1032 			saved_export = op_ctx->fsal_export;
1033 			op_ctx->fsal_export = junction_export->fsal_export;
1034 	
1035 			fsal_prepare_attrs(&attrs2,
1036 					   op_ctx->fsal_export->exp_ops
1037 						.fs_supported_attrs(op_ctx->fsal_export)
1038 						| ATTR_RDATTR_ERR);
1039 	
1040 			status = junction_obj->obj_ops->getattrs(junction_obj, &attrs2);
1041 	
1042 			if (!FSAL_IS_ERROR(status)) {
1043 				/* Now call the callback again with that. */
1044 				state->cb_state = CB_JUNCTION;
1045 				status.major = state->cb(&state->cb_parms,
1046 							 junction_obj,
1047 							 &attrs2,
1048 							 junction_export
1049 							     ->exp_mounted_on_file_id,
1050 							 cookie,
1051 							 state->cb_state);
1052 	
1053 				state->cb_state = CB_ORIGINAL;
1054 			}
1055 	
1056 			fsal_release_attrs(&attrs2);
1057 	
1058 			/* Release our refs */
1059 			op_ctx->fsal_export = saved_export;
1060 	
1061 			junction_obj->obj_ops->put_ref(junction_obj);
1062 			put_gsh_export(junction_export);
1063 	
1064 			/* state->cb (nfs4_readdir_callback) saved op_ctx
1065 			 * ctx_export and fsal_export. Restore them here
1066 			 */
1067 			(void)state->cb(&state->cb_parms, NULL, NULL,
1068 					 0, 0, CB_PROBLEM);
1069 		}
1070 	
1071 		if (!state->cb_parms.in_result) {
1072 			/* Protocol layers NEVER do readahead. */
1073 			retval = DIR_TERMINATE;
1074 			goto out;
1075 		}
1076 	
1077 		(*state->cb_nfound)++;
1078 	
1079 	out:
1080 	
1081 		/* Put the ref on obj that readdir took */
1082 		obj->obj_ops->put_ref(obj);
1083 	
1084 		return retval;
1085 	}
1086 	
1087 	/**
1088 	 * @brief Reads a directory
1089 	 *
1090 	 * This function iterates over the directory entries  and invokes a supplied
1091 	 * callback function for each one.
1092 	 *
1093 	 * @param[in]  directory The directory to be read
1094 	 * @param[in]  cookie    Starting cookie for the readdir operation
1095 	 * @param[out] eod_met   Whether the end of directory was met
1096 	 * @param[in]  attrmask  Attributes requested, used for permission checking
1097 	 *                       really all that matters is ATTR_ACL and any attrs
1098 	 *                       at all, specifics never actually matter.
1099 	 * @param[in]  cb        The callback function to receive entries
1100 	 * @param[in]  opaque    A pointer passed to be passed in
1101 	 *                       fsal_readdir_cb_parms
1102 	 *
1103 	 * @return FSAL status
1104 	 */
1105 	
1106 	fsal_status_t fsal_readdir(struct fsal_obj_handle *directory,
1107 			    uint64_t cookie,
1108 			    unsigned int *nbfound,
1109 			    bool *eod_met,
1110 			    attrmask_t attrmask,
1111 			    helper_readdir_cb cb,
1112 			    void *opaque)
1113 	{
1114 		fsal_status_t fsal_status = {0, 0};
1115 		fsal_status_t cb_status = {0, 0};
1116 		struct fsal_populate_cb_state state;
1117 	
1118 		*nbfound = 0;
1119 	
1120 		/* The access mask corresponding to permission to list directory
1121 		   entries */
1122 		fsal_accessflags_t access_mask =
1123 		    (FSAL_MODE_MASK_SET(FSAL_R_OK) |
1124 		     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR));
1125 		fsal_accessflags_t access_mask_attr =
1126 		    (FSAL_MODE_MASK_SET(FSAL_R_OK) | FSAL_MODE_MASK_SET(FSAL_X_OK) |
1127 		     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR) |
1128 		     FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_EXECUTE));
1129 	
1130 		/* readdir can be done only with a directory */
1131 		if (directory->type != DIRECTORY) {
1132 			LogDebug(COMPONENT_NFS_READDIR, "Not a directory");
1133 			return fsalstat(ERR_FSAL_NOTDIR, 0);
1134 		}
1135 	
1136 		/* Adjust access mask if ACL is asked for.
1137 		 * NOTE: We intentionally do NOT check ACE4_READ_ATTR.
1138 		 */
1139 		if ((attrmask & ATTR_ACL) != 0) {
1140 			access_mask |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_READ_ACL);
1141 			access_mask_attr |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_READ_ACL);
1142 		}
1143 	
1144 		fsal_status = fsal_access(directory, access_mask);
1145 		if (FSAL_IS_ERROR(fsal_status)) {
1146 			LogDebug(COMPONENT_NFS_READDIR,
1147 				 "permission check for directory status=%s",
1148 				 fsal_err_txt(fsal_status));
1149 			return fsal_status;
1150 		}
1151 		if (attrmask != 0) {
1152 			/* Check for access permission to get attributes */
1153 			fsal_status_t attr_status = fsal_access(directory,
1154 								access_mask_attr);
1155 			if (FSAL_IS_ERROR(attr_status))
1156 				LogDebug(COMPONENT_NFS_READDIR,
1157 					 "permission check for attributes status=%s",
1158 					 fsal_err_txt(attr_status));
1159 			state.cb_parms.attr_allowed = !FSAL_IS_ERROR(attr_status);
1160 		} else {
1161 			/* No attributes requested. */
1162 			state.cb_parms.attr_allowed = false;
1163 		}
1164 	
1165 		state.directory = directory;
1166 		state.status = &cb_status;
1167 		state.cb = cb;
1168 		state.last_cookie = 0;
1169 		state.cb_parms.opaque = opaque;
1170 		state.cb_parms.in_result = true;
1171 		state.cb_parms.name = NULL;
1172 		state.cb_state = CB_ORIGINAL;
1173 		state.cb_nfound = nbfound;
1174 		state.attrmask = attrmask;
1175 	
1176 		fsal_status = directory->obj_ops->readdir(directory, &cookie,
1177 							 (void *)&state,
1178 							 populate_dirent,
1179 							 attrmask,
1180 							 eod_met);
1181 	
1182 		return fsal_status;
1183 	}
1184 	
1185 	/**
1186 	 *
1187 	 * @brief Remove a name from a directory.
1188 	 *
1189 	 * @param[in] parent  Handle for the parent directory to be managed
1190 	 * @param[in] name    Name to be removed
1191 	 *
1192 	 * @retval fsal_status_t
1193 	 */
1194 	
1195 	fsal_status_t
1196 	fsal_remove(struct fsal_obj_handle *parent, const char *name)
1197 	{
1198 		struct fsal_obj_handle *to_remove_obj = NULL;
1199 		fsal_status_t status = { 0, 0 };
1200 	
1201 		if (parent->type != DIRECTORY) {
1202 			status = fsalstat(ERR_FSAL_NOTDIR, 0);
1203 			goto out_no_obj;
1204 		}
1205 	
1206 		/* Looks up for the entry to remove */
1207 		status = fsal_lookup(parent, name, &to_remove_obj, NULL);
1208 		if (FSAL_IS_ERROR(status)) {
1209 			LogFullDebug(COMPONENT_FSAL, "lookup %s failure %s",
1210 				     name, fsal_err_txt(status));
1211 			return status;
1212 		}
1213 	
1214 		/* Do not remove a junction node or an export root. */
1215 		if (obj_is_junction(to_remove_obj)) {
1216 			LogCrit(COMPONENT_FSAL, "Attempt to remove export %s", name);
1217 			status = fsalstat(ERR_FSAL_NOTEMPTY, 0);
1218 			goto out;
1219 		}
1220 	
1221 		if (state_deleg_conflict(to_remove_obj, true)) {
1222 			LogDebug(COMPONENT_FSAL, "Found an existing delegation for %s",
1223 				  name);
1224 			status = fsalstat(ERR_FSAL_DELAY, 0);
1225 			goto out;
1226 		}
1227 	
1228 		LogFullDebug(COMPONENT_FSAL, "%s", name);
1229 	
1230 		/* Make sure the to_remove_obj is closed since unlink of an
1231 		 * open file results in 'silly rename' on certain platforms.
1232 		 */
1233 		status = fsal_close(to_remove_obj);
1234 	
1235 		if (FSAL_IS_ERROR(status)) {
1236 			/* non-fatal error. log the warning and move on */
1237 			LogCrit(COMPONENT_FSAL,
1238 				"Error closing %s before unlink: %s.",
1239 				name, fsal_err_txt(status));
1240 		}
1241 	
1242 	#ifdef ENABLE_RFC_ACL
1243 		status = fsal_remove_access(parent, to_remove_obj,
1244 					    (to_remove_obj->type == DIRECTORY));
1245 		if (FSAL_IS_ERROR(status))
1246 			goto out;
1247 	#endif /* ENABLE_RFC_ACL */
1248 	
1249 		status = parent->obj_ops->unlink(parent, to_remove_obj, name);
1250 	
1251 		if (FSAL_IS_ERROR(status)) {
1252 			LogFullDebug(COMPONENT_FSAL, "unlink %s failure %s",
1253 				     name, fsal_err_txt(status));
1254 			goto out;
1255 		}
1256 	
1257 	out:
1258 	
1259 		to_remove_obj->obj_ops->put_ref(to_remove_obj);
1260 	
1261 	out_no_obj:
1262 	
1263 		LogFullDebug(COMPONENT_FSAL, "remove %s: status=%s", name,
1264 			     fsal_err_txt(status));
1265 	
1266 		return status;
1267 	}
1268 	
1269 	/**
1270 	 * @brief Renames a file
1271 	 *
1272 	 * @param[in] dir_src  The source directory
1273 	 * @param[in] oldname  The current name of the file
1274 	 * @param[in] dir_dest The destination directory
1275 	 * @param[in] newname  The name to be assigned to the object
1276 	 *
1277 	 * @return FSAL status
1278 	 */
1279 	fsal_status_t fsal_rename(struct fsal_obj_handle *dir_src,
1280 				  const char *oldname,
1281 				  struct fsal_obj_handle *dir_dest,
1282 				  const char *newname)
1283 	{
1284 		fsal_status_t fsal_status = { 0, 0 };
1285 		struct fsal_obj_handle *lookup_src = NULL;
1286 	
1287 		if ((dir_src->type != DIRECTORY) || (dir_dest->type != DIRECTORY))
1288 			return fsalstat(ERR_FSAL_NOTDIR, 0);
1289 	
1290 		/* Check for . and .. on oldname and newname. */
1291 		if (oldname[0] == '\0' || newname[0] == '\0'
1292 		    || !strcmp(oldname, ".") || !strcmp(oldname, "..")
1293 		    || !strcmp(newname, ".") || !strcmp(newname, "..")) {
1294 			return fsalstat(ERR_FSAL_INVAL, 0);
1295 		}
1296 	
1297 		/* Check for object existence in source directory */
1298 		fsal_status = fsal_lookup(dir_src, oldname, &lookup_src, NULL);
1299 	
1300 		if (FSAL_IS_ERROR(fsal_status)) {
1301 			LogDebug(COMPONENT_FSAL,
1302 				 "Rename (%p,%s)->(%p,%s) : source doesn't exist",
1303 				 dir_src, oldname, dir_dest, newname);
1304 			goto out;
1305 		}
1306 	
1307 		/* Do not rename a junction node or an export root. */
1308 		if (obj_is_junction(lookup_src)) {
1309 			LogCrit(COMPONENT_FSAL, "Attempt to rename export %s", oldname);
1310 			fsal_status = fsalstat(ERR_FSAL_NOTEMPTY, 0);
1311 			goto out;
1312 		}
1313 	
1314 		/* Don't allow rename of an object as parent of itself */
1315 		if (dir_dest == lookup_src) {
1316 			fsal_status = fsalstat(ERR_FSAL_INVAL, 0);
1317 			goto out;
1318 		}
1319 		/* *
1320 		 * added conflicts check for destination in MDCACHE layer
1321 		 */
1322 		if (state_deleg_conflict(lookup_src, true)) {
1323 			LogDebug(COMPONENT_FSAL, "Found an existing delegation for %s",
1324 				  oldname);
1325 			fsal_status = fsalstat(ERR_FSAL_DELAY, 0);
1326 			goto out;
1327 		}
1328 	
1329 		LogFullDebug(COMPONENT_FSAL, "about to call FSAL rename");
1330 	
1331 		fsal_status = dir_src->obj_ops->rename(lookup_src, dir_src, oldname,
1332 						      dir_dest, newname);
1333 	
1334 		LogFullDebug(COMPONENT_FSAL, "returned from FSAL rename");
1335 	
1336 		if (FSAL_IS_ERROR(fsal_status)) {
1337 	
1338 			LogFullDebug(COMPONENT_FSAL,
1339 				     "FSAL rename failed with %s",
1340 				     fsal_err_txt(fsal_status));
1341 	
1342 			goto out;
1343 		}
1344 	
1345 	out:
1346 		if (lookup_src) {
1347 			/* Note that even with a junction, this object is in the same
1348 			 * export since that would be the junction node, NOT the export
1349 			 * root node on the other side of the junction.
1350 			 */
1351 			lookup_src->obj_ops->put_ref(lookup_src);
1352 		}
1353 	
1354 		return fsal_status;
1355 	}
1356 	
1357 	/**
1358 	 * @brief Opens a file by name or by handle.
1359 	 *
1360 	 * This function accomplishes both a LOOKUP if necessary and an open.
1361 	 *
1362 	 * Returns with an LRU reference held on the entry.
1363 	 *
1364 	 * state can be NULL which indicates a stateless open (such as via the
1365 	 * NFS v3 CREATE operation).
1366 	 *
1367 	 * At least the mode attribute must be set if createmode is not FSAL_NO_CREATE.
1368 	 * Some FSALs may still have to pass a mode on a create call for exclusive,
1369 	 * and even with FSAL_NO_CREATE, and empty set of attributes MUST be passed.
1370 	 *
1371 	 * The caller is expected to invoke fsal_release_attrs to release any
1372 	 * resources held by the set attributes. The FSAL layer MAY have added an
1373 	 * inherited ACL.
1374 	 *
1375 	 * @param[in]     in_obj     Parent directory or obj
1376 	 * @param[in,out] state      state_t to operate on
1377 	 * @param[in]     openflags  Details of how to open the file
1378 	 * @param[in]     createmode Mode if creating
1379 	 * @param[in]     name       If name is not NULL, entry is the parent directory
1380 	 * @param[in]     attr       Attributes to set on the file
1381 	 * @param[in]     verifier   Verifier to use with exclusive create
1382 	 * @param[out]    obj        New entry for the opened file
1383 	 *
1384 	 * @return FSAL status
1385 	 */
1386 	
1387 	fsal_status_t fsal_open2(struct fsal_obj_handle *in_obj,
1388 				 struct state_t *state,
1389 				 fsal_openflags_t openflags,
1390 				 enum fsal_create_mode createmode,
1391 				 const char *name,
1392 				 struct attrlist *attr,
1393 				 fsal_verifier_t verifier,
1394 				 struct fsal_obj_handle **obj,
1395 				 struct attrlist *attrs_out)
1396 	{
1397 		fsal_status_t status = { 0, 0 };
1398 		bool caller_perm_check = false;
1399 		char *reason;
1400 	
1401 		*obj = NULL;
1402 	
1403 		if (attr != NULL)
1404 			LogAttrlist(COMPONENT_FSAL, NIV_FULL_DEBUG,
1405 				    "attrs ", attr, false);
1406 	
1407 		/* Handle attribute size = 0 here, normalize to FSAL_O_TRUNC
1408 		 * instead of setting ATTR_SIZE.
1409 		 */
1410 		if (attr != NULL &&
1411 		    FSAL_TEST_MASK(attr->valid_mask, ATTR_SIZE) &&
1412 		    attr->filesize == 0) {
1413 			LogFullDebug(COMPONENT_FSAL, "Truncate");
1414 			/* Handle truncate to zero on open */
1415 			openflags |= FSAL_O_TRUNC;
1416 			/* Don't set the size if we later set the attributes */
1417 			FSAL_UNSET_MASK(attr->valid_mask, ATTR_SIZE);
1418 		}
1419 	
1420 		if (createmode >= FSAL_EXCLUSIVE && verifier == NULL)
1421 			return fsalstat(ERR_FSAL_INVAL, 0);
1422 		if (name)
1423 			return open2_by_name(in_obj, state, openflags, createmode,
1424 					     name, attr, verifier, obj, attrs_out);
1425 	
1426 		/* No name, directories don't make sense */
1427 		if (in_obj->type == DIRECTORY) {
1428 			if (createmode != FSAL_NO_CREATE)
1429 				return fsalstat(ERR_FSAL_INVAL, 0);
1430 	
1431 			return fsalstat(ERR_FSAL_ISDIR, 0);
1432 		}
1433 	
1434 		if (in_obj->type != REGULAR_FILE)
1435 			return fsalstat(ERR_FSAL_BADTYPE, 0);
1436 	
1437 		/* Do a permission check on the file before opening. */
1438 		status = check_open_permission(in_obj, openflags,
1439 					       createmode >= FSAL_EXCLUSIVE, &reason);
1440 	
1441 		if (FSAL_IS_ERROR(status)) {
1442 			LogDebug(COMPONENT_FSAL,
1443 				 "Not opening file file %s%s",
1444 				 reason, fsal_err_txt(status));
1445 			return status;
1446 		}
1447 	
1448 		/* Open THIS entry, so name must be NULL. The attr are passed in case
1449 		 * this is a create with size = 0. We pass the verifier because this
1450 		 * might be an exclusive recreate replay and we want the FSAL to
1451 		 * check the verifier.
1452 		 */
1453 		status = in_obj->obj_ops->open2(in_obj,
1454 					       state,
1455 					       openflags,
1456 					       createmode,
1457 					       NULL,
1458 					       attr,
1459 					       verifier,
1460 					       obj,
1461 					       attrs_out,
1462 					       &caller_perm_check);
1463 	
1464 		if (!FSAL_IS_ERROR(status)) {
1465 			/* Get a reference to the entry. */
1466 			*obj = in_obj;
1467 			in_obj->obj_ops->get_ref(in_obj);
1468 		}
1469 	
1470 		return status;
1471 	}
1472 	
1473 	/**
1474 	 * @brief Re-Opens a file by handle.
1475 	 *
1476 	 * This MAY be used to open a file the first time if there is no need for
1477 	 * open by name or create semantics.
1478 	 *
1479 	 * @param[in]     obj              File to operate on
1480 	 * @param[in,out] state            state_t to operate on
1481 	 * @param[in]     openflags        Details of how to open the file
1482 	 * @param[in]     check_permission Indicate if permission should be checked
1483 	 *
1484 	 * @return FSAL status
1485 	 */
1486 	
1487 	fsal_status_t fsal_reopen2(struct fsal_obj_handle *obj,
1488 				   struct state_t *state,
1489 				   fsal_openflags_t openflags,
1490 				   bool check_permission)
1491 	{
1492 		fsal_status_t status = { 0, 0 };
1493 		char *reason = "FSAL reopen failed - ";
1494 	
1495 		if (check_permission) {
1496 			/* Do a permission check on the file before re-opening. */
1497 			status = check_open_permission(obj, openflags, false, &reason);
1498 			if (FSAL_IS_ERROR(status))
1499 				goto out;
1500 		}
1501 	
1502 		/* Re-open the entry in the FSAL.
1503 		 */
1504 		status = obj->obj_ops->reopen2(obj, state, openflags);
1505 	
1506 	 out:
1507 	
1508 		if (FSAL_IS_ERROR(status)) {
1509 			LogDebug(COMPONENT_FSAL,
1510 				 "Not re-opening file file %s%s",
1511 				 reason, fsal_err_txt(status));
1512 		}
1513 	
1514 		return status;
1515 	}
1516 	
1517 	
1518 	fsal_status_t fsal_statfs(struct fsal_obj_handle *obj,
1519 				  fsal_dynamicfsinfo_t *dynamicinfo)
1520 	{
1521 		fsal_status_t fsal_status;
1522 		struct fsal_export *export;
1523 	
1524 		export = op_ctx->ctx_export->fsal_export;
1525 		/* Get FSAL to get dynamic info */
1526 		fsal_status =
1527 		    export->exp_ops.get_fs_dynamic_info(export, obj, dynamicinfo);
1528 		LogFullDebug(COMPONENT_FSAL,
1529 			     "dynamicinfo: {total_bytes = %" PRIu64
1530 			     ", free_bytes = %" PRIu64 ", avail_bytes = %" PRIu64
1531 			     ", total_files = %" PRIu64 ", free_files = %" PRIu64
1532 			     ", avail_files = %" PRIu64 "}", dynamicinfo->total_bytes,
1533 			     dynamicinfo->free_bytes, dynamicinfo->avail_bytes,
1534 			     dynamicinfo->total_files, dynamicinfo->free_files,
1535 			     dynamicinfo->avail_files);
1536 		return fsal_status;
1537 	}
1538 	
1539 	/**
1540 	 * @brief Verify an exclusive create replay when the file is already open.
1541 	 *
1542 	 * This may not be necessary in real life, however, pynfs definitely has a
1543 	 * test case that walks this path.
1544 	 *
1545 	 * @param[in]     obj        File to verify
1546 	 * @param[in]     verifier   Verifier to use with exclusive create
1547 	 *
1548 	 * @return FSAL status
1549 	 */
1550 	
1551 	fsal_status_t fsal_verify2(struct fsal_obj_handle *obj,
1552 				   fsal_verifier_t verifier)
1553 	{
1554 		if (!obj->obj_ops->check_verifier(obj, verifier)) {
1555 			/* Verifier check failed. */
1556 			return fsalstat(ERR_FSAL_EXIST, 0);
1557 		}
1558 	
1559 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
1560 	}
1561 	
1562 	/**
1563 	 * @brief Fetch optional attributes
1564 	 *
1565 	 * The request_mask should be set in attrs_out indicating which attributes
1566 	 * are desired. If ATTR_RDATTR_ERR is set, and the getattrs fails,
1567 	 * the error ERR_FSAL_NO_ERROR will be returned, however the attributes
1568 	 * valid_mask will be set to ATTR_RDATTR_ERR. Otherwise, if
1569 	 * ATTR_RDATTR_ERR is not set and the getattrs fails, the error returned
1570 	 * by getattrs will be returned.
1571 	 *
1572 	 * @param[in]     obj_hdl   Object to get attributes for.
1573 	 * @param[in,out] attrs_out Optional attributes for the object
1574 	 *
1575 	 * @return FSAL status.
1576 	 **/
1577 	fsal_status_t get_optional_attrs(struct fsal_obj_handle *obj_hdl,
1578 					 struct attrlist *attrs_out)
1579 	{
1580 		fsal_status_t status;
1581 	
1582 		if (attrs_out == NULL)
1583 			return fsalstat(ERR_FSAL_NO_ERROR, 0);
1584 	
1585 		status = obj_hdl->obj_ops->getattrs(obj_hdl, attrs_out);
1586 	
1587 		if (FSAL_IS_ERROR(status)) {
1588 			if (attrs_out->request_mask & ATTR_RDATTR_ERR) {
1589 				/* Indicate the failure of requesting attributes by
1590 				 * marking the ATTR_RDATTR_ERR in the mask.
1591 				 */
1592 				attrs_out->valid_mask = ATTR_RDATTR_ERR;
1593 				status = fsalstat(ERR_FSAL_NO_ERROR, 0);
1594 			} /* otherwise let the error stand. */
1595 		}
1596 	
1597 		return status;
1598 	}
1599 	
1600 	/**
1601 	 * @brief Callback to implement syncronous read and write
1602 	 *
1603 	 * @param[in] obj		Object being acted on
1604 	 * @param[in] ret		Return status of call
1605 	 * @param[in] args		Args for read call
1606 	 * @param[in] caller_data	Data for caller
1607 	 */
1608 	static void sync_cb(struct fsal_obj_handle *obj, fsal_status_t ret,
1609 				 void *args, void *caller_data)
1610 	{
1611 		struct async_process_data *data = caller_data;
1612 	
1613 		/* Fixup FSAL_SHARE_DENIED status */
1614 		if (ret.major == ERR_FSAL_SHARE_DENIED)
1615 			ret = fsalstat(ERR_FSAL_LOCKED, 0);
1616 	
1617 		data->ret = ret;
1618 	
1619 		/* Let caller know we are done. */
1620 	
1621 		PTHREAD_MUTEX_lock(data->mutex);
1622 	
1623 		data->done = true;
1624 	
1625 		pthread_cond_signal(data->cond);
1626 	
1627 		PTHREAD_MUTEX_unlock(data->mutex);
1628 	}
1629 	
1630 	void fsal_read(struct fsal_obj_handle *obj_hdl,
1631 		       bool bypass,
1632 		       struct fsal_io_arg *arg,
1633 		       struct async_process_data *data)
1634 	{
1635 		obj_hdl->obj_ops->read2(obj_hdl, bypass, sync_cb, arg, data);
1636 	
1637 		PTHREAD_MUTEX_lock(data->mutex);
1638 	
1639 		while (!data->done) {
1640 			int rc = pthread_cond_wait(data->cond, data->mutex);
1641 	
1642 			assert(rc == 0);
1643 		}
1644 	
1645 		PTHREAD_MUTEX_unlock(data->mutex);
1646 	}
1647 	
1648 	void fsal_write(struct fsal_obj_handle *obj_hdl,
1649 			bool bypass,
1650 			struct fsal_io_arg *arg,
1651 			struct async_process_data *data)
1652 	{
1653 		obj_hdl->obj_ops->write2(obj_hdl, bypass, sync_cb, arg, data);
1654 	
1655 		PTHREAD_MUTEX_lock(data->mutex);
1656 	
1657 		while (!data->done) {
1658 			int rc = pthread_cond_wait(data->cond, data->mutex);
1659 	
1660 			assert(rc == 0);
1661 		}
1662 	
1663 		PTHREAD_MUTEX_unlock(data->mutex);
1664 	}
1665 	
1666 	/** @} */
1667