1 /*
2  * Copyright (C) 2021 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <syslog.h>
28 #include <errno.h>
29 #include <inttypes.h>
30 #ifdef HAVE_SYS_MMAN_H
31 #include <sys/mman.h>
32 #endif
33 
34 #include "MFSCommunication.h"
35 #include "massert.h"
36 #include "slogger.h"
37 #include "datapack.h"
38 #include "filesystem.h"
39 #include "xattr.h"
40 #include "dictionary.h"
41 #include "bio.h"
42 #include "glue.h"
43 
44 typedef struct _xattrpair {
45 	struct _xattrpair *next;
46 	void *dictname;
47 	void *dictvalue;
48 } xattrpair;
49 
50 typedef struct _xattrentry {
51 	struct _xattrentry *next;
52 	uint32_t inode;
53 	//	uint32_t anleng;
54 	//	uint32_t avleng;
55 	xattrpair *pairhead;
56 } xattrentry;
57 
58 #define LOHASH_BITS 20
59 #define ENTRY_TYPE xattrentry
60 #define GLUE_FN_NAME_PREFIX(Y) GLUE(xattr,Y)
61 #define HASH_ARGS_TYPE_LIST uint32_t inode
62 #define HASH_ARGS_LIST inode
63 #define GLUE_HASH_TAB_PREFIX(Y) GLUE(xattr,Y)
64 
GLUE_FN_NAME_PREFIX(_cmp)65 static inline int GLUE_FN_NAME_PREFIX(_cmp)(ENTRY_TYPE *e,HASH_ARGS_TYPE_LIST) {
66 	return (e->inode==inode);
67 }
68 
GLUE_FN_NAME_PREFIX(_hash)69 static inline uint32_t GLUE_FN_NAME_PREFIX(_hash)(HASH_ARGS_TYPE_LIST) {
70 	return inode;
71 }
72 
GLUE_FN_NAME_PREFIX(_ehash)73 static inline uint32_t GLUE_FN_NAME_PREFIX(_ehash)(ENTRY_TYPE *e) {
74 	return e->inode;
75 }
76 
77 #include "hash_begin.h"
78 
xattr_cleanup_node(xattrentry * xe)79 static inline void xattr_cleanup_node(xattrentry *xe) {
80 	xattrpair *xp;
81 	while ((xp=xe->pairhead)!=NULL) {
82 		dict_dec_ref(xp->dictname);
83 		dict_dec_ref(xp->dictvalue);
84 		xe->pairhead = xp->next;
85 		free(xp);
86 	}
87 }
88 
89 /* externals */
90 
xattr_namecheck(uint8_t anleng,const uint8_t * attrname)91 int xattr_namecheck(uint8_t anleng,const uint8_t *attrname) {
92 	uint32_t i;
93 	for (i=0 ; i<anleng ; i++) {
94 		if (attrname[i]=='\0') {
95 			return -1;
96 		}
97 	}
98 	return 0;
99 }
100 
xattr_removeinode(uint32_t inode)101 void xattr_removeinode(uint32_t inode) {
102 	xattrentry *xe;
103 	xe = GLUE_FN_NAME_PREFIX(_find)(inode);
104 	if (xe) {
105 		xattr_cleanup_node(xe);
106 		GLUE_FN_NAME_PREFIX(_delete)(xe);
107 		free(xe);
108 	}
109 }
110 
xattr_setattr(uint32_t inode,uint8_t anleng,const uint8_t * attrname,uint32_t avleng,const uint8_t * attrvalue,uint8_t mode)111 uint8_t xattr_setattr(uint32_t inode,uint8_t anleng,const uint8_t *attrname,uint32_t avleng,const uint8_t *attrvalue,uint8_t mode) {
112 	xattrentry *xe;
113 	xattrpair *xp,**xpp;
114 	void *dictname;
115 	uint32_t inode_anleng;
116 
117 	if (anleng + 1 > MFS_XATTR_LIST_MAX) {
118 		return MFS_ERROR_ERANGE;
119 	}
120 	xe = GLUE_FN_NAME_PREFIX(_find)(inode);
121 	if (mode==MFS_XATTR_REPLACE_ONLY || mode==MFS_XATTR_REMOVE) {
122 		if (xe==NULL) {
123 			return MFS_ERROR_ENOATTR;
124 		}
125 		dictname = dict_search(attrname,anleng);
126 		if (dictname==NULL) {
127 			return MFS_ERROR_ENOATTR;
128 		}
129 	} else {
130 		if (xe==NULL) {
131 			xe = malloc(sizeof(xattrentry));
132 			passert(xe);
133 			xe->inode = inode;
134 //			xe->anleng = 0;
135 //			xe->avleng = 0;
136 			xe->pairhead = NULL;
137 			GLUE_FN_NAME_PREFIX(_add)(xe);
138 			fs_set_xattrflag(inode);
139 		}
140 		dictname = dict_insert(attrname,anleng); // inc_ref
141 	}
142 
143 	inode_anleng = 0;
144 	xpp = &(xe->pairhead);
145 	while ((xp=*xpp)!=NULL) {
146 		if (xp->dictname==dictname) {
147 			switch (mode) {
148 				case MFS_XATTR_CREATE_ONLY:
149 					dict_dec_ref(dictname);
150 					return MFS_ERROR_EEXIST;
151 				case MFS_XATTR_REMOVE:
152 					// remove
153 //					xe->anleng -= (anleng + 1);
154 //					xe->avleng -= dict_get_leng(xp->dictvalue);
155 					dict_dec_ref(xp->dictname);
156 					dict_dec_ref(xp->dictvalue);
157 					*xpp = xp->next;
158 					free(xp);
159 					if (xe->pairhead==NULL) {
160 						GLUE_FN_NAME_PREFIX(_delete)(xe);
161 						free(xe);
162 						fs_del_xattrflag(inode);
163 					}
164 					return MFS_STATUS_OK;
165 				case MFS_XATTR_CREATE_OR_REPLACE:
166 					dict_dec_ref(dictname);
167 					// no break on purpose
168 					nobreak;
169 				case MFS_XATTR_REPLACE_ONLY:
170 					if (avleng>MFS_XATTR_SIZE_MAX) {
171 						return MFS_ERROR_ERANGE;
172 					}
173 //					xe->avleng -= dict_get_leng(xp->dictvalue);
174 					dict_dec_ref(xp->dictvalue);
175 					xp->dictvalue = dict_insert(attrvalue,avleng);
176 //					xe->avleng += avleng;
177 					return MFS_STATUS_OK;
178 				default:
179 					dict_dec_ref(dictname);
180 					return MFS_ERROR_EINVAL;
181 			}
182 		}
183 		inode_anleng += dict_get_leng(xp->dictname)+1;
184 		xpp = &(xp->next);
185 	}
186 	if (mode==MFS_XATTR_REPLACE_ONLY || mode==MFS_XATTR_REMOVE) {
187 		return MFS_ERROR_ENOATTR;
188 	}
189 	if (inode_anleng + anleng + 1 > MFS_XATTR_LIST_MAX) {
190 		dict_dec_ref(dictname);
191 		return MFS_ERROR_ERANGE;
192 	}
193 	xp = malloc(sizeof(xattrpair));
194 	xp->dictname = dictname;
195 	xp->dictvalue = dict_insert(attrvalue,avleng);
196 	xp->next = xe->pairhead;
197 	xe->pairhead = xp;
198 //	xe->anleng += anleng + 1;
199 //	xe->avleng += avleng;
200 	return MFS_STATUS_OK;
201 }
202 
xattr_getattr(uint32_t inode,uint8_t anleng,const uint8_t * attrname,uint32_t * avleng,const uint8_t ** attrvalue)203 uint8_t xattr_getattr(uint32_t inode,uint8_t anleng,const uint8_t *attrname,uint32_t *avleng,const uint8_t **attrvalue) {
204 	xattrentry *xe;
205 	xattrpair *xp;
206 	void *dictname;
207 
208 	xe = GLUE_FN_NAME_PREFIX(_find)(inode);
209 	if (xe) {
210 		dictname = dict_search(attrname,anleng);
211 		if (dictname!=NULL) {
212 			for (xp=xe->pairhead ; xp!=NULL ; xp=xp->next) {
213 				if (xp->dictname==dictname) {
214 					*avleng = dict_get_leng(xp->dictvalue);
215 					*attrvalue = dict_get_ptr(xp->dictvalue);
216 					return MFS_STATUS_OK;
217 				}
218 			}
219 		}
220 	}
221 	return MFS_ERROR_ENOATTR;
222 }
223 
xattr_listattr_leng(uint32_t inode,void ** xanode,uint32_t * xasize)224 uint8_t xattr_listattr_leng(uint32_t inode,void **xanode,uint32_t *xasize) {
225 	xattrentry *xe;
226 	xattrpair *xp;
227 	uint32_t inode_anleng;
228 
229 	inode_anleng = 0;
230 	xe = GLUE_FN_NAME_PREFIX(_find)(inode);
231 	if (xe!=NULL) {
232 		for (xp=xe->pairhead ; xp!=NULL ; xp=xp->next) {
233 			inode_anleng += dict_get_leng(xp->dictname) + 1;
234 		}
235 	}
236 	if (inode_anleng>MFS_XATTR_LIST_MAX) {
237 		return MFS_ERROR_ERANGE;
238 	}
239 	*xanode = (void*)xe;
240 	*xasize = inode_anleng;
241 	return MFS_STATUS_OK;
242 }
243 
xattr_listattr_data(void * xanode,uint8_t * xabuff)244 void xattr_listattr_data(void *xanode,uint8_t *xabuff) {
245 	xattrentry *xe = (xattrentry*)xanode;
246 	xattrpair *xp;
247 	uint32_t i;
248 
249 	i = 0;
250 	if (xe!=NULL) {
251 		for (xp=xe->pairhead ; xp!=NULL ; xp=xp->next) {
252 			memcpy(xabuff+i,dict_get_ptr(xp->dictname),dict_get_leng(xp->dictname));
253 			i+=dict_get_leng(xp->dictname);
254 			xabuff[i++]=0;
255 		}
256 	}
257 }
258 
xattr_copy(uint32_t srcinode,uint32_t dstinode)259 uint8_t xattr_copy(uint32_t srcinode,uint32_t dstinode) {
260 	xattrentry *sxe,*dxe;
261 	xattrpair *sxp,*dxp,**xpt;
262 
263 	sxe = GLUE_FN_NAME_PREFIX(_find)(srcinode);
264 	if (sxe==NULL) {
265 		return 0;
266 	}
267 	dxe = malloc(sizeof(xattrentry));
268 	passert(dxe);
269 	dxe->inode = dstinode;
270 	dxe->pairhead = NULL;
271 	xpt = &(dxe->pairhead);
272 	GLUE_FN_NAME_PREFIX(_add)(dxe);
273 	for (sxp=sxe->pairhead ; sxp!=NULL ; sxp=sxp->next) {
274 		dxp = malloc(sizeof(xattrpair));
275 		passert(dxp);
276 		dxp->dictname = sxp->dictname;
277 		dxp->dictvalue = sxp->dictvalue;
278 		dict_inc_ref(dxp->dictname);
279 		dict_inc_ref(dxp->dictvalue);
280 		dxp->next = NULL;
281 		*xpt = dxp;
282 		xpt = &(dxp->next);
283 	}
284 	return 1;
285 }
286 
xattr_cleanup(void)287 void xattr_cleanup(void) {
288 	uint16_t i;
289 	uint32_t j;
290 	xattrentry *xe,*xen;
291 	for (i=0 ; i<HASHTAB_HISIZE ; i++) {
292 		if (GLUE_HASH_TAB_PREFIX(hashtab)[i]!=NULL) {
293 			for (j=0 ; j<HASHTAB_LOSIZE ; j++) {
294 				for (xe=GLUE_HASH_TAB_PREFIX(hashtab)[i][j] ; xe!=NULL ; xe=xen) {
295 					xattr_cleanup_node(xe);
296 					xen = xe->next;
297 					free(xe);
298 				}
299 				GLUE_HASH_TAB_PREFIX(hashtab)[i][j] = NULL;
300 			}
301 		}
302 	}
303 	GLUE_FN_NAME_PREFIX(_hash_cleanup)();
304 }
305 
xattr_store(bio * fd)306 uint8_t xattr_store(bio *fd) {
307 	uint8_t hdrbuff[4+1+4];
308 	uint8_t *ptr;
309 	uint16_t i;
310 	uint32_t j;
311 	uint32_t anleng,avleng;
312 	xattrentry *xe;
313 	xattrpair *xp;
314 
315 	if (fd==NULL) {
316 		return 0x10;
317 	}
318 	for (i=0 ; i<HASHTAB_HISIZE ; i++) {
319 		if (GLUE_HASH_TAB_PREFIX(hashtab)[i]!=NULL) {
320 			for (j=0 ; j<HASHTAB_LOSIZE ; j++) {
321 				for (xe=GLUE_HASH_TAB_PREFIX(hashtab)[i][j] ; xe!=NULL ; xe=xe->next) {
322 					for (xp=xe->pairhead ; xp!=NULL ; xp=xp->next) {
323 						anleng = dict_get_leng(xp->dictname);
324 						avleng = dict_get_leng(xp->dictvalue);
325 						if (anleng>255) {
326 							anleng = 255;
327 						}
328 						ptr = hdrbuff;
329 						put32bit(&ptr,xe->inode);
330 						put8bit(&ptr,anleng);
331 						put32bit(&ptr,avleng);
332 						if (bio_write(fd,hdrbuff,4+1+4)!=(4+1+4)) {
333 							syslog(LOG_NOTICE,"write error");
334 							return 0xFF;
335 						}
336 						if (bio_write(fd,dict_get_ptr(xp->dictname),anleng)!=anleng) {
337 							syslog(LOG_NOTICE,"write error");
338 							return 0xFF;
339 						}
340 						if (avleng>0) {
341 							if (bio_write(fd,dict_get_ptr(xp->dictvalue),avleng)!=avleng) {
342 								syslog(LOG_NOTICE,"write error");
343 								return 0xFF;
344 							}
345 						}
346 					}
347 				}
348 			}
349 		}
350 	}
351 	memset(hdrbuff,0,4+1+4);
352 	if (bio_write(fd,hdrbuff,4+1+4)!=(4+1+4)) {
353 		syslog(LOG_NOTICE,"write error");
354 		return 0xFF;
355 	}
356 	return 0;
357 }
358 
xattr_load(bio * fd,uint8_t mver,int ignoreflag)359 int xattr_load(bio *fd,uint8_t mver,int ignoreflag) {
360 	uint8_t hdrbuff[4+1+4];
361 	uint8_t *databuff;
362 	const uint8_t *ptr;
363 	uint32_t inode;
364 	uint32_t lastinode;
365 	uint8_t anleng;
366 	uint32_t avleng;
367 	uint8_t nl=1;
368 	xattrentry *xe;
369 	xattrpair *xp,**xpt;
370 
371 	(void)mver;
372 	xpt = NULL;
373 
374 	databuff = malloc(MFS_XATTR_NAME_MAX+MFS_XATTR_SIZE_MAX);
375 	passert(databuff);
376 	lastinode = 0;
377 	while (1) {
378 		if (bio_read(fd,hdrbuff,4+1+4)!=(4+1+4)) {
379 			int err = errno;
380 			if (nl) {
381 				fputc('\n',stderr);
382 				// nl=0;
383 			}
384 			errno = err;
385 			mfs_errlog(LOG_ERR,"loading xattr: read error");
386 			free(databuff);
387 			return -1;
388 		}
389 		ptr = hdrbuff;
390 		inode = get32bit(&ptr);
391 		anleng = get8bit(&ptr);
392 		avleng = get32bit(&ptr);
393 		if (inode==0) {
394 			free(databuff);
395 			return 1;
396 		}
397 		if (fs_check_inode(inode)==0) { // inode does not exist - skip it
398 			bio_skip(fd,anleng+avleng);
399 			continue;
400 		}
401 		if (anleng==0) {
402 			if (nl) {
403 				fputc('\n',stderr);
404 				nl=0;
405 			}
406 			mfs_syslog(LOG_ERR,"loading xattr: empty name");
407 			if (ignoreflag) {
408 				bio_skip(fd,anleng+avleng);
409 				continue;
410 			} else {
411 				free(databuff);
412 				return -1;
413 			}
414 		}
415 #if MFS_XATTR_NAME_MAX<255
416 		if (avleng>MFS_XATTR_SIZE_MAX || anleng>MFS_XATTR_NAME_MAX) {
417 #else
418 		if (avleng>MFS_XATTR_SIZE_MAX) {
419 #endif
420 			if (nl) {
421 				fputc('\n',stderr);
422 				nl=0;
423 			}
424 			mfs_syslog(LOG_ERR,"loading xattr: value oversized");
425 			if (ignoreflag) {
426 				bio_skip(fd,anleng+avleng);
427 				continue;
428 			} else {
429 				free(databuff);
430 				return -1;
431 			}
432 		}
433 		if (inode!=lastinode) {
434 			xe = GLUE_FN_NAME_PREFIX(_find)(inode);
435 			if (xe==NULL) {
436 				xe = malloc(sizeof(xattrentry));
437 				passert(xe);
438 				xe->inode = inode;
439 				xe->pairhead = NULL;
440 				GLUE_FN_NAME_PREFIX(_add)(xe);
441 				fs_set_xattrflag(inode);
442 				xpt = &(xe->pairhead);
443 			} else { // import from old file format
444 				xpt = &(xe->pairhead);
445 				while ((*xpt)!=NULL) {
446 					xpt = &((*xpt)->next);
447 				}
448 			}
449 			lastinode = inode;
450 		}
451 		if (bio_read(fd,databuff,anleng+avleng)!=(anleng+avleng)) {
452 			int err = errno;
453 			if (nl) {
454 				fputc('\n',stderr);
455 				// nl=0;
456 			}
457 			errno = err;
458 			mfs_errlog(LOG_ERR,"loading xattr: read error");
459 			free(databuff);
460 			return -1;
461 		}
462 		xp = malloc(sizeof(xattrpair));
463 		xp->dictname = dict_insert(databuff,anleng);
464 		xp->dictvalue = dict_insert(databuff+anleng,avleng);
465 		xp->next = NULL;
466 		*xpt = xp;
467 		xpt = &(xp->next);
468 	}
469 }
470 
471 int xattr_init(void) {
472 	GLUE_FN_NAME_PREFIX(_hash_init)();
473 	return 0;
474 }
475 
476 #include "hash_end.h"
477 
478 #undef LOHASH_BITS
479 #undef ENTRY_TYPE
480 #undef GLUE_FN_NAME_PREFIX
481 #undef HASH_ARGS_TYPE_LIST
482 #undef HASH_ARGS_LIST
483 #undef GLUE_HASH_TAB_PREFIX
484