blob: 6e9c81e73d255b3598bd1ccfbf7c987781c840ef [file] [log] [blame]
/*
* vim:noexpandtab:shiftwidth=8:tabstop=8:
*
* Copyright CEA/DAM/DIF (2011)
* contributeur : Philippe DENIEL philippe.deniel@cea.fr
* Thomas LEIBOVICI thomas.leibovici@cea.fr
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* ---------------------------------------
*/
/**
* \file 9p_xattrwalk.c
* \brief 9P version
*
* 9p_xattrwalk.c : _9P_interpretor, request XATTRWALK
*
*
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include "nfs_core.h"
#include "log.h"
#include "fsal.h"
#include "9p.h"
#define XATTRS_ARRAY_LEN 100
int _9p_xattrwalk(struct _9p_request_data *req9p, u32 *plenout, char *preply)
{
char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
u16 *msgtag = NULL;
u32 *fid = NULL;
u32 *attrfid = NULL;
u16 *name_len;
char *name_str;
size_t attrsize = 0;
fsal_status_t fsal_status;
char name[MAXNAMLEN+1];
fsal_xattrent_t xattrs_arr[XATTRS_ARRAY_LEN];
int eod_met = false;
unsigned int nb_xattrs_read = 0;
unsigned int i = 0;
char *xattr_cursor = NULL;
unsigned int tmplen = 0;
struct _9p_fid *pfid = NULL;
struct _9p_fid *pxattrfid = NULL;
/* Get data */
_9p_getptr(cursor, msgtag, u16);
_9p_getptr(cursor, fid, u32);
_9p_getptr(cursor, attrfid, u32);
LogDebug(COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u",
(u32) *msgtag, *fid, *attrfid);
_9p_getstr(cursor, name_len, name_str);
if (*name_len == 0)
LogDebug(COMPONENT_9P,
"TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=(LIST XATTR)",
(u32) *msgtag, *fid, *attrfid);
else
LogDebug(COMPONENT_9P,
"TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=%.*s",
(u32) *msgtag, *fid, *attrfid, *name_len, name_str);
if (*fid >= _9P_FID_PER_CONN)
return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);
if (*attrfid >= _9P_FID_PER_CONN)
return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);
pfid = req9p->pconn->fids[*fid];
/* Check that it is a valid fid */
if (pfid == NULL || pfid->pentry == NULL) {
LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
return _9p_rerror(req9p, msgtag, EIO, plenout, preply);
}
pxattrfid = gsh_calloc(1, sizeof(struct _9p_fid));
/* set op_ctx, it will be useful if FSAL is later called */
_9p_init_opctx(pfid, req9p);
/* Initiate xattr's fid by copying file's fid in it.
* Don't copy the state_t pointer.
*/
memcpy((char *)pxattrfid, (char *)pfid, sizeof(struct _9p_fid));
pxattrfid->state = NULL;
if (*name_len >= sizeof(name)) {
LogDebug(COMPONENT_9P, "request with name too long (%u)",
*name_len);
return _9p_rerror(req9p, msgtag, ENAMETOOLONG, plenout,
preply);
}
snprintf(name, sizeof(name), "%.*s", *name_len, name_str);
pxattrfid->specdata.xattr.xattr_content = gsh_malloc(XATTR_BUFFERSIZE);
if (*name_len == 0) {
/* xattrwalk is used with an empty name,
* this is a listxattr request */
fsal_status =
pxattrfid->pentry->obj_ops.list_ext_attrs(pxattrfid->pentry,
FSAL_XATTR_RW_COOKIE, /* Start with RW cookie,
* hiding RO ones */
xattrs_arr,
XATTRS_ARRAY_LEN, /** @todo fix static length */
&nb_xattrs_read,
&eod_met);
if (FSAL_IS_ERROR(fsal_status)) {
gsh_free(pxattrfid->specdata.xattr.xattr_content);
gsh_free(pxattrfid);
return _9p_rerror(req9p, msgtag,
_9p_tools_errno(fsal_status), plenout,
preply);
}
/* if all xattrent are not read,
* returns ERANGE as listxattr does */
if (eod_met != true) {
gsh_free(pxattrfid->specdata.xattr.xattr_content);
gsh_free(pxattrfid);
return _9p_rerror(req9p, msgtag, ERANGE,
plenout, preply);
}
xattr_cursor = pxattrfid->specdata.xattr.xattr_content;
attrsize = 0;
for (i = 0; i < nb_xattrs_read; i++) {
tmplen =
snprintf(xattr_cursor, MAXNAMLEN, "%s",
xattrs_arr[i].xattr_name);
xattr_cursor[tmplen] = '\0'; /* Just to be sure */
/* +1 for trailing '\0' */
xattr_cursor += tmplen + 1;
attrsize += tmplen + 1;
/* Make sure not to go beyond the buffer */
if (attrsize > XATTR_BUFFERSIZE) {
gsh_free(pxattrfid->specdata.xattr.
xattr_content);
gsh_free(pxattrfid);
return _9p_rerror(req9p, msgtag, ERANGE,
plenout, preply);
}
}
} else {
/* xattrwalk has a non-empty name, use regular setxattr */
fsal_status =
pxattrfid->pentry->obj_ops.getextattr_id_by_name(
pxattrfid->pentry,
name,
&pxattrfid->specdata.xattr.xattr_id);
if (FSAL_IS_ERROR(fsal_status)) {
gsh_free(pxattrfid->specdata.xattr.xattr_content);
gsh_free(pxattrfid);
/* ENOENT for xattr is ENOATTR */
if (fsal_status.major == ERR_FSAL_NOENT)
return _9p_rerror(req9p, msgtag, ENOATTR,
plenout, preply);
else
return _9p_rerror(req9p, msgtag,
_9p_tools_errno(fsal_status),
plenout, preply);
}
fsal_status =
pxattrfid->pentry->obj_ops.getextattr_value_by_name(
pxattrfid->pentry,
name,
pxattrfid->specdata.xattr.
xattr_content, XATTR_BUFFERSIZE,
&attrsize);
if (FSAL_IS_ERROR(fsal_status)) {
gsh_free(pxattrfid->specdata.xattr.xattr_content);
gsh_free(pxattrfid);
/* fsal_status.minor is a valid errno code */
return _9p_rerror(req9p, msgtag,
fsal_status.minor, plenout, preply);
}
}
req9p->pconn->fids[*attrfid] = pxattrfid;
/* Increments refcount as we're manually making a new copy */
pfid->pentry->obj_ops.get_ref(pfid->pentry);
/* hold reference on gdata */
uid2grp_hold_group_data(pxattrfid->gdata);
get_gsh_export_ref(pfid->export);
get_9p_user_cred_ref(pfid->ucred);
if (pxattrfid->ppentry != NULL) {
/* Increments refcount for ppentry */
pxattrfid->ppentry->obj_ops.get_ref(pxattrfid->ppentry);
}
/* Build the reply */
_9p_setinitptr(cursor, preply, _9P_RXATTRWALK);
_9p_setptr(cursor, msgtag, u16);
_9p_setvalue(cursor, attrsize, u64);
_9p_setendptr(cursor, preply);
_9p_checkbound(cursor, preply, plenout);
LogDebug(COMPONENT_9P,
"RXATTRWALK: tag=%u fid=%u attrfid=%u name=%.*s size=%llu",
(u32) *msgtag, *fid, *attrfid, *name_len, name_str,
(unsigned long long)attrsize);
return 1;
} /* _9p_xattrwalk */