1 /* Copyright (C) 1997 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 /** \file attribute.c Attribute handling functions. */
9 #include "server_cmd.lsg.h"
20 static struct osl_table
*attribute_table
;
21 static int greatest_att_bitnum
;
23 /** The columns of the attribute table. */
24 enum attribute_table_columns
{
25 /** The bit number (0-63). */
27 /** The name of the attribute. */
29 /** Number of columns in this table. */
33 static int char_compare(const struct osl_object
*obj1
, const struct osl_object
*obj2
)
35 const unsigned char *c1
= (const unsigned char*)obj1
->data
;
36 const unsigned char *c2
= (const unsigned char*)obj2
->data
;
44 static struct osl_column_description att_cols
[] = {
46 .storage_type
= OSL_MAPPED_STORAGE
,
47 .storage_flags
= OSL_RBTREE
| OSL_FIXED_SIZE
| OSL_UNIQUE
,
49 .compare_function
= char_compare
,
53 .storage_type
= OSL_MAPPED_STORAGE
,
54 .storage_flags
= OSL_RBTREE
| OSL_UNIQUE
,
56 .compare_function
= string_compare
,
60 static struct osl_table_description attribute_table_desc
= {
62 .num_columns
= NUM_ATT_COLUMNS
,
64 .column_descriptions
= att_cols
67 static void find_greatest_att_bitnum(void)
72 struct osl_object obj
= {.data
= &c
, .size
= 1};
73 if (osl_get_row(attribute_table
, ATTCOL_BITNUM
, &obj
,
75 greatest_att_bitnum
= c
;
79 PARA_INFO_LOG("no attributes\n");
80 greatest_att_bitnum
= -E_NO_ATTRIBUTES
;
84 * Retrieve the identifier (number) of an attribute.
86 * \param att_name The name of the attribute.
87 * \param bitnum Result pointer.
89 * \return Positive on success, negative on errors.
91 int get_attribute_bitnum_by_name(const char *att_name
, unsigned char *bitnum
)
93 struct osl_object obj
= {.data
= (char *)att_name
,
94 .size
= strlen(att_name
) + 1};
96 int ret
= osl(osl_get_row(attribute_table
, ATTCOL_NAME
, &obj
, &row
));
100 ret
= osl(osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
, &obj
));
103 *bitnum
= *(unsigned char *)obj
.data
;
107 /** Data passed to the action function of lsatt */
108 static int print_attribute(struct osl_table
*table
, struct osl_row
*row
,
109 const char *name
, void *data
)
111 struct afs_callback_arg
*aca
= data
;
112 bool l_given
= SERVER_CMD_OPT_GIVEN(LSATT
, LONG
, aca
->lpr
);
113 struct osl_object bitnum_obj
;
117 para_printf(&aca
->pbout
, "%s\n", name
);
120 ret
= osl(osl_get_object(table
, row
, ATTCOL_BITNUM
, &bitnum_obj
));
122 para_printf(&aca
->pbout
, "%s: %s\n", name
, para_strerror(-ret
));
125 para_printf(&aca
->pbout
, "%u\t%s\n", *(unsigned char*)bitnum_obj
.data
,
130 static int com_lsatt_callback(struct afs_callback_arg
*aca
)
132 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(LSATT
);
133 bool i_given
, r_given
;
135 struct pattern_match_data pmd
= {
136 .table
= attribute_table
,
137 .loop_col_num
= ATTCOL_NAME
,
138 .match_col_num
= ATTCOL_NAME
,
139 .pm_flags
= PM_NO_PATTERN_MATCHES_EVERYTHING
,
141 .action
= print_attribute
144 ret
= lls(lls_deserialize_parse_result(aca
->query
.data
, cmd
, &aca
->lpr
));
147 i_given
= SERVER_CMD_OPT_GIVEN(LSATT
, ID_SORT
, aca
->lpr
);
148 r_given
= SERVER_CMD_OPT_GIVEN(LSATT
, REVERSE
, aca
->lpr
);
151 pmd
.loop_col_num
= ATTCOL_BITNUM
;
153 pmd
.pm_flags
|= PM_REVERSE_LOOP
;
154 ret
= for_each_matching_row(&pmd
);
157 if (pmd
.num_matches
== 0)
160 lls_free_parse_result(aca
->lpr
, cmd
);
164 static int com_lsatt(struct command_context
*cc
, struct lls_parse_result
*lpr
)
166 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(LSATT
);
167 return send_lls_callback_request(com_lsatt_callback
, cmd
, lpr
, cc
);
169 EXPORT_SERVER_CMD_HANDLER(lsatt
);
171 struct addatt_event_data
{
173 unsigned char bitnum
;
176 static int com_addatt_callback(struct afs_callback_arg
*aca
)
178 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(ADDATT
);
183 ret
= lls(lls_deserialize_parse_result(aca
->query
.data
, cmd
, &aca
->lpr
));
185 num_inputs
= lls_num_inputs(aca
->lpr
);
186 for (i
= 0; i
< num_inputs
; i
++) {
187 const char *name
= lls_input(i
, aca
->lpr
);
188 struct osl_object objs
[NUM_ATT_COLUMNS
];
190 unsigned char bitnum
;
191 struct addatt_event_data aed
;
194 if (len
== 0 || name
[len
- 1] == '-' || name
[len
- 1] == '+') {
195 para_printf(&aca
->pbout
,
196 "invalid attribute name: %s\n", name
);
199 ret
= get_attribute_bitnum_by_name(name
, &bitnum
);
201 para_printf(&aca
->pbout
,
202 "attribute \"%s\" already exists\n", name
);
205 if (ret
!= -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND
)) /* error */
207 objs
[ATTCOL_BITNUM
].size
= 1;
208 /* find smallest unused attribute */
209 for (bitnum
= 0; bitnum
< 64; bitnum
++) {
210 objs
[ATTCOL_BITNUM
].data
= &bitnum
;
211 ret
= osl(osl_get_row(attribute_table
, ATTCOL_BITNUM
,
212 &objs
[ATTCOL_BITNUM
], &row
));
213 if (ret
== -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND
))
214 break; /* this bitnum is unused, use it */
215 if (ret
< 0) /* error */
217 /* this bit is already in use, try next bit */
220 ret
= -E_ATT_TABLE_FULL
;
223 objs
[ATTCOL_NAME
].data
= (char *)name
;
224 objs
[ATTCOL_NAME
].size
= len
+ 1;
225 ret
= osl(osl_add_row(attribute_table
, objs
));
230 ret
= afs_event(ATTRIBUTE_ADD
, &aca
->pbout
, &aed
);
233 greatest_att_bitnum
= PARA_MAX(greatest_att_bitnum
, (int)bitnum
);
237 para_printf(&aca
->pbout
, "error while adding %s\n",
238 lls_input(i
, aca
->lpr
));
242 static int com_addatt(struct command_context
*cc
, struct lls_parse_result
*lpr
)
244 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(ADDATT
);
246 int ret
= lls(lls_check_arg_count(lpr
, 1, 64, &errctx
));
249 send_errctx(cc
, errctx
);
252 return send_lls_callback_request(com_addatt_callback
, cmd
, lpr
, cc
);
254 EXPORT_SERVER_CMD_HANDLER(addatt
);
256 static int com_mvatt_callback(struct afs_callback_arg
*aca
)
258 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(MVATT
);
259 const char *old
, *new;
260 struct osl_object obj
;
264 ret
= lls(lls_deserialize_parse_result(aca
->query
.data
, cmd
, &aca
->lpr
));
266 old
= lls_input(0, aca
->lpr
);
267 new = lls_input(1, aca
->lpr
);
268 obj
.data
= (char *)old
;
269 obj
.size
= strlen(old
) + 1;
270 ret
= osl(osl_get_row(attribute_table
, ATTCOL_NAME
, &obj
, &row
));
273 obj
.data
= (char *)new;
274 obj
.size
= strlen(new) + 1;
275 /* The update fails if the destination attribute exists. */
276 ret
= osl(osl_update_object(attribute_table
, row
, ATTCOL_NAME
, &obj
));
279 para_printf(&aca
->pbout
, "cannot rename %s to %s\n", old
, new);
281 ret
= afs_event(ATTRIBUTE_RENAME
, &aca
->pbout
, NULL
);
282 lls_free_parse_result(aca
->lpr
, cmd
);
286 static int com_mvatt(struct command_context
*cc
, struct lls_parse_result
*lpr
)
288 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(MVATT
);
290 int ret
= lls(lls_check_arg_count(lpr
, 2, 2, &errctx
));
292 send_errctx(cc
, errctx
);
295 return send_lls_callback_request(com_mvatt_callback
, cmd
, lpr
, cc
);
297 EXPORT_SERVER_CMD_HANDLER(mvatt
);
299 static int remove_attribute(struct osl_table
*table
, struct osl_row
*row
,
300 const char *name
, void *data
)
302 struct afs_callback_arg
*aca
= data
;
304 struct rmatt_event_data red
= {.name
= name
};
306 ret
= get_attribute_bitnum_by_name(name
, &red
.bitnum
);
308 para_printf(&aca
->pbout
, "cannot remove %s\n", name
);
311 para_printf(&aca
->pbout
, "removing attribute %s\n", name
);
312 ret
= osl(osl_del_row(table
, row
));
314 para_printf(&aca
->pbout
, "cannot remove %s\n", name
);
317 return afs_event(ATTRIBUTE_REMOVE
, &aca
->pbout
, &red
);
320 static int com_rmatt_callback(struct afs_callback_arg
*aca
)
322 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(RMATT
);
324 struct pattern_match_data pmd
= {
325 .table
= attribute_table
,
326 .loop_col_num
= ATTCOL_BITNUM
,
327 .match_col_num
= ATTCOL_NAME
,
329 .action
= remove_attribute
331 ret
= lls(lls_deserialize_parse_result(aca
->query
.data
, cmd
, &aca
->lpr
));
334 ret
= for_each_matching_row(&pmd
);
337 if (pmd
.num_matches
== 0)
340 lls_free_parse_result(aca
->lpr
, cmd
);
344 static int com_rmatt(struct command_context
*cc
, struct lls_parse_result
*lpr
)
346 const struct lls_command
*cmd
= SERVER_CMD_CMD_PTR(RMATT
);
348 int ret
= lls(lls_check_arg_count(lpr
, 1, INT_MAX
, &errctx
));
351 send_errctx(cc
, errctx
);
354 return send_lls_callback_request(com_rmatt_callback
, cmd
, lpr
, cc
);
356 EXPORT_SERVER_CMD_HANDLER(rmatt
);
359 * Return a binary representation of the given attribute value.
361 * \param atts Pointer to the attribute value.
364 * This function prints a string of at most 64 characters plus the terminating
365 * \p NULL character into \a buf which must be provided by the caller and at
366 * least 65 bytes long. The "x" character is used for set attributes and "-" is
367 * used for unset attributes.
369 * In practice, not all 64 attributes are defined. In this case, the function
370 * only prints \a N + 1 characters where \a N is the greatest id of a defined
373 void get_attribute_bitmap(const uint64_t *atts
, char *buf
)
376 const uint64_t one
= 1;
378 for (i
= 0; i
<= greatest_att_bitnum
; i
++)
379 buf
[greatest_att_bitnum
- i
] = (*atts
& (one
<< i
))? 'x' : '-';
384 * Get a string containing the set attributes in text form.
386 * \param atts The attribute bitmap.
387 * \param delim The delimiter to separate matching attribute names.
388 * \param text Result pointer.
390 * \return Positive on success, negative on errors. If no attributes have
391 * been defined, \a *text is NULL.
393 int get_attribute_text(uint64_t *atts
, const char *delim
, char **text
)
396 const uint64_t one
= 1;
399 if (greatest_att_bitnum
< 0) { /* no attributes available */
400 *text
= para_strdup("(no attributes available)");
403 for (i
= 0; i
<= greatest_att_bitnum
; i
++) {
404 unsigned char bn
= i
;
405 struct osl_object obj
= {.data
= &bn
, .size
= 1};
408 if (!(*atts
& (one
<< i
)))
410 ret
= osl(osl_get_row(attribute_table
, ATTCOL_BITNUM
, &obj
, &row
));
413 ret
= osl(osl_get_object(attribute_table
, row
, ATTCOL_NAME
, &obj
));
417 char *tmp
= make_message("%s%s%s", *text
, delim
, (char *)obj
.data
);
421 *text
= para_strdup(obj
.data
);
423 if (!*text
) /* no attributes set */
424 *text
= para_strdup("");
431 static int att_logical_or(struct osl_row
*row
, void *data
)
433 uint64_t *att_mask
= data
, one
= 1;
434 struct osl_object bitnum_obj
;
435 int ret
= osl_get_object(attribute_table
, row
, ATTCOL_BITNUM
, &bitnum_obj
);
439 *att_mask
|= one
<< *(unsigned char *)bitnum_obj
.data
;
444 * Compute the attribute bit mask and check each afs info bitmap.
446 * \param aca The query field of \a aca is ignored.
448 * This iterates over all attributes in the attribute table and computes the
449 * logical or of 1 << b where b is the bit number of the attribute. The
450 * resulting bit mask is passed to aft_check_attributes() which performs the
455 * \sa \ref aft_check_attributes().
457 int attribute_check_callback(struct afs_callback_arg
*aca
)
460 uint64_t att_mask
= 0; /* bits corresponding to a attributes */
462 ret
= osl_rbtree_loop(attribute_table
, ATTCOL_BITNUM
, &att_mask
,
465 PARA_ERROR_LOG("attribute table loop failed: %s\n",
466 para_strerror(-ret
));
469 return aft_check_attributes(att_mask
, &aca
->pbout
);
473 * Close the attribute table.
475 * \sa \ref osl_close_table().
477 static void attribute_close(void)
479 osl_close_table(attribute_table
, OSL_MARK_CLEAN
);
480 attribute_table
= NULL
;
484 * Open the attribute table.
486 * \param dir The database directory.
488 * \return Positive on success, negative on errors.
490 * \sa \ref osl_open_table().
492 static int attribute_open(const char *dir
)
496 attribute_table_desc
.dir
= dir
;
497 ret
= osl(osl_open_table(&attribute_table_desc
, &attribute_table
));
498 greatest_att_bitnum
= -1; /* no atts available */
500 find_greatest_att_bitnum();
503 attribute_table
= NULL
;
504 if (ret
== -OSL_ERRNO_TO_PARA_ERROR(E_OSL_NOENT
))
509 static int attribute_create(const char *dir
)
511 attribute_table_desc
.dir
= dir
;
512 return osl(osl_create_table(&attribute_table_desc
));
516 * Initialize the attribute table structure.
518 * \param t The table structure to initialize.
520 void attribute_init(struct afs_table
*t
)
522 t
->open
= attribute_open
;
523 t
->close
= attribute_close
;
524 t
->create
= attribute_create
;