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