1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright CEA/DAM/DIF  (2011)
5    	 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
6    	 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
7    	 *
8    	 *
9    	 * This program is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public
11   	 * License as published by the Free Software Foundation; either
12   	 * version 3 of the License, or (at your option) any later version.
13   	 *
14   	 * This program is distributed in the hope that it will be useful,
15   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * You should have received a copy of the GNU Lesser General Public
20   	 * License along with this library; if not, write to the Free Software
21   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
22   	 *
23   	 * ---------------------------------------
24   	 */
25   	
26   	/**
27   	 * \file    9p_xattrwalk.c
28   	 * \brief   9P version
29   	 *
30   	 * 9p_xattrwalk.c : _9P_interpretor, request XATTRWALK
31   	 *
32   	 *
33   	 */
34   	
35   	#include "config.h"
36   	#include <stdio.h>
37   	#include <string.h>
38   	#include <pthread.h>
39   	#include <sys/stat.h>
40   	#include <sys/types.h>
41   	#include "os/xattr.h"
42   	#include "nfs_core.h"
43   	#include "log.h"
44   	#include "fsal.h"
45   	#include "9p.h"
46   	
47   	#define XATTRS_ARRAY_LEN 100
48   	
49   	int _9p_xattrwalk(struct _9p_request_data *req9p, u32 *plenout, char *preply)
50   	{
51   		char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
52   		u16 *msgtag = NULL;
53   		u32 *fid = NULL;
54   		u32 *attrfid = NULL;
55   		u16 *name_len;
56   		char *name_str;
57   		size_t attrsize = 0;
58   	
59   		fsal_status_t fsal_status;
60   		char name[MAXNAMLEN+1];
(1) Event stack_use_local_overflow: Local variable "xattrs_arr" uses 27200 bytes of stack space, which exceeds the maximum single use of 10000 bytes.
61   		fsal_xattrent_t xattrs_arr[XATTRS_ARRAY_LEN];
62   		int eod_met = false;
63   		unsigned int nb_xattrs_read = 0;
64   		unsigned int i = 0;
65   		char *xattr_cursor = NULL;
66   		unsigned int tmplen = 0;
67   	
68   		struct _9p_fid *pfid = NULL;
69   		struct _9p_fid *pxattrfid = NULL;
70   	
71   		/* Get data */
72   		_9p_getptr(cursor, msgtag, u16);
73   		_9p_getptr(cursor, fid, u32);
74   		_9p_getptr(cursor, attrfid, u32);
75   	
76   		LogDebug(COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u",
77   			 (u32) *msgtag, *fid, *attrfid);
78   	
79   		_9p_getstr(cursor, name_len, name_str);
80   	
81   		if (*name_len == 0)
82   			LogDebug(COMPONENT_9P,
83   				 "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=(LIST XATTR)",
84   				 (u32) *msgtag, *fid, *attrfid);
85   		else
86   			LogDebug(COMPONENT_9P,
87   				 "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=%.*s",
88   				 (u32) *msgtag, *fid, *attrfid, *name_len, name_str);
89   	
90   		if (*fid >= _9P_FID_PER_CONN)
91   			return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);
92   	
93   		if (*attrfid >= _9P_FID_PER_CONN)
94   			return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);
95   	
96   		pfid = req9p->pconn->fids[*fid];
97   		/* Check that it is a valid fid */
98   		if (pfid == NULL || pfid->pentry == NULL) {
99   			LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
100  			return _9p_rerror(req9p, msgtag, EIO, plenout, preply);
101  		}
102  	
103  		if (*name_len >= sizeof(name)) {
104  			LogDebug(COMPONENT_9P, "request with name too long (%u)",
105  				 *name_len);
106  			return _9p_rerror(req9p, msgtag, ENAMETOOLONG, plenout,
107  					  preply);
108  		}
109  	
110  		pxattrfid = gsh_calloc(1, sizeof(struct _9p_fid));
111  	
112  		/* set op_ctx, it will be useful if FSAL is later called */
113  		_9p_init_opctx(pfid, req9p);
114  	
115  		/* Initiate xattr's fid by copying file's fid in it.
116  		 * Don't copy the state_t pointer.
117  		 */
118  		memcpy((char *)pxattrfid, (char *)pfid, sizeof(struct _9p_fid));
119  		pxattrfid->state = NULL;
120  	
121  		snprintf(name, sizeof(name), "%.*s", *name_len, name_str);
122  	
123  		pxattrfid->xattr = gsh_malloc(sizeof(*pxattrfid->xattr) +
124  					      XATTR_BUFFERSIZE);
125  	
126  		if (*name_len == 0) {
127  			/* xattrwalk is used with an empty name,
128  			 * this is a listxattr request */
129  			fsal_status = pxattrfid->pentry->obj_ops->list_ext_attrs(
130  				pxattrfid->pentry,
131  				FSAL_XATTR_RW_COOKIE,	/* Start with RW cookie,
132  							 * hiding RO ones */
133  				xattrs_arr,
134  				XATTRS_ARRAY_LEN, /** @todo fix static length */
135  				&nb_xattrs_read,
136  				&eod_met);
137  	
138  			if (FSAL_IS_ERROR(fsal_status)) {
139  				gsh_free(pxattrfid->xattr);
140  				gsh_free(pxattrfid);
141  				return _9p_rerror(req9p, msgtag,
142  						  _9p_tools_errno(fsal_status), plenout,
143  						  preply);
144  			}
145  	
146  			/* if all xattrent are not read,
147  			 * returns ERANGE as listxattr does */
148  			if (eod_met != true) {
149  				gsh_free(pxattrfid->xattr);
150  				gsh_free(pxattrfid);
151  				return _9p_rerror(req9p, msgtag, ERANGE,
152  						  plenout, preply);
153  			}
154  	
155  			xattr_cursor = pxattrfid->xattr->xattr_content;
156  			attrsize = 0;
157  			for (i = 0; i < nb_xattrs_read; i++) {
158  				tmplen = strnlen(xattrs_arr[i].xattr_name, MAXNAMLEN);
159  				/* Make sure not to go beyond the buffer
160  				 * @todo realloc here too */
161  				if (attrsize + tmplen + 1 > XATTR_BUFFERSIZE) {
162  					gsh_free(pxattrfid->xattr);
163  					gsh_free(pxattrfid);
164  					return _9p_rerror(req9p, msgtag, ERANGE,
165  							  plenout, preply);
166  				}
167  	
168  				memcpy(xattr_cursor, xattrs_arr[i].xattr_name, tmplen);
169  				xattr_cursor[tmplen] = '\0';
170  				/* +1 for trailing '\0' */
171  				xattr_cursor += tmplen + 1;
172  				attrsize += tmplen + 1;
173  	
174  			}
175  		} else {
176  			/* xattrwalk has a non-empty name, use regular getxattr */
177  			fsal_status =
178  			    pxattrfid->pentry->obj_ops->getextattr_value_by_name(
179  						     pxattrfid->pentry, name,
180  						     pxattrfid->xattr->xattr_content,
181  						     XATTR_BUFFERSIZE,
182  						     &attrsize);
183  	
184  			if (fsal_status.minor == ERANGE) {
185  				/* we need a bigger buffer, do one more request with
186  				 * 0-size to get length and reallocate/try again */
187  				fsal_status =
188  				   pxattrfid->pentry->obj_ops->getextattr_value_by_name(
189  						     pxattrfid->pentry, name,
190  						     pxattrfid->xattr->xattr_content,
191  						     0, &attrsize);
192  				if (FSAL_IS_ERROR(fsal_status)) {
193  					gsh_free(pxattrfid->xattr);
194  					gsh_free(pxattrfid);
195  	
196  					/* fsal_status.minor is a valid errno code */
197  					return _9p_rerror(req9p, msgtag,
198  							  fsal_status.minor, plenout,
199  							  preply);
200  				}
201  	
202  				/* Check our own limit too before reallocating */
203  				if (attrsize > _9P_XATTR_MAX_SIZE) {
204  					gsh_free(pxattrfid->xattr);
205  					gsh_free(pxattrfid);
206  	
207  					return _9p_rerror(req9p, msgtag, E2BIG,
208  							  plenout, preply);
209  				}
210  	
211  				pxattrfid->xattr = gsh_realloc(pxattrfid->xattr,
212  						sizeof(*pxattrfid->xattr) + attrsize);
213  	
214  				fsal_status =
215  				   pxattrfid->pentry->obj_ops->getextattr_value_by_name(
216  						     pxattrfid->pentry, name,
217  						     pxattrfid->xattr->xattr_content,
218  						     attrsize, &attrsize);
219  			}
220  			if (FSAL_IS_ERROR(fsal_status)) {
221  				gsh_free(pxattrfid->xattr);
222  				gsh_free(pxattrfid);
223  	
224  				/* ENOENT for xattr is ENOATTR */
225  				if (fsal_status.major == ERR_FSAL_NOENT)
226  					return _9p_rerror(req9p, msgtag, ENOATTR,
227  							  plenout, preply);
228  	
229  				/* fsal_status.minor is a valid errno code */
230  				return _9p_rerror(req9p, msgtag,
231  						  fsal_status.minor, plenout, preply);
232  			}
233  		}
234  		pxattrfid->xattr->xattr_size = attrsize;
235  		pxattrfid->xattr->xattr_write = _9P_XATTR_READ_ONLY;
236  	
237  		req9p->pconn->fids[*attrfid] = pxattrfid;
238  	
239  		/* Increments refcount as we're manually making a new copy */
240  		pfid->pentry->obj_ops->get_ref(pfid->pentry);
241  	
242  		/* hold reference on gdata */
243  		uid2grp_hold_group_data(pxattrfid->gdata);
244  	
245  		get_gsh_export_ref(pfid->fid_export);
246  		get_9p_user_cred_ref(pfid->ucred);
247  	
248  		if (pxattrfid->ppentry != NULL) {
249  			/* Increments refcount for ppentry */
250  			pxattrfid->ppentry->obj_ops->get_ref(pxattrfid->ppentry);
251  		}
252  	
253  		/* Build the reply */
254  		_9p_setinitptr(cursor, preply, _9P_RXATTRWALK);
255  		_9p_setptr(cursor, msgtag, u16);
256  	
257  		_9p_setvalue(cursor, attrsize, u64);
258  	
259  		_9p_setendptr(cursor, preply);
260  		_9p_checkbound(cursor, preply, plenout);
261  	
262  		LogDebug(COMPONENT_9P,
263  			 "RXATTRWALK: tag=%u fid=%u attrfid=%u name=%.*s size=%llu",
264  			 (u32) *msgtag, *fid, *attrfid, *name_len, name_str,
265  			 (unsigned long long)attrsize);
266  	
267  		return 1;
268  	}				/* _9p_xattrwalk */
269