Программистское. Скучное.
Mar. 3rd, 2005 05:40 amПосле 5 лет тотальной Perl лоботомии я понял, что забыл С практически начисто... Провозился 2 дня с вылизыванием 80 строчек кода :( Но до сих пор не уверен, что сделал все правильно. Так что, если кто присоветует, что тут еще можно улучщить - пишите :) Да, если по скорости какие-то оптимизации - тоже :)
Да, код под FreeBSD5 :)
Кстати, не уверен, насколько верно передавать int a в функцию с void* ptr через &a, а потом приводить через *(int*)ptr. Но в теории, размера указателя может не хватить, чтобы поместить в него int(хотя до сих пор работало:)).
Да, код под FreeBSD5 :)
#include <errno.h>
#include <sys/types.h>
#include <sys/extattr.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
static struct {
int space;
const char *name;
size_t len;
}
extattr[] = {
{ EXTATTR_NAMESPACE_SYSTEM, “system.”, sizeof(“system.”) },
{ EXTATTR_NAMESPACE_USER, “user.”, sizeof(“user.”) },
};
ssize_t my_listxattr (int type, const void *arg, char *list, size_t size) {
ssize_t list_size, tot_size = 0;
int i, t, len;
char *buf;
/* Iterate through extattr(2) namespaces */
for(t = 0; t < sizeof(extattr)/sizeof(extattr[0]); t++) {
switch(type) {
case 0:
list_size = extattr_list_file((const char*)arg, extattr[t].space, list, size);
break;
case 1:
list_size = extattr_list_link((const char*)arg, extattr[t].space, list, size);
break;
case 2:
list_size = extattr_list_fd(*(int*)arg, extattr[t].space, list, size);
break;
default:
errno = ENOSYS;
return -1;
}
/* Some error happened. Errno should be set by previous call */
if(list_size < 0)
return -1;
/* No attributes */
if(list_size == 0)
continue;
/* XXX: Call with an empty buffer may be used to calculate
necessary buffer size. Unfortunately, we can't say, how
many attributes were returned, so here is the potential
problem with the emulation.
*/
if(list == NULL) {
/* For sure, at least one attribute exists. */
tot_size += list_size + extattr[t].len - 1;
continue;
}
/* Count necessary offset to fit namespace prefixes */
len = 0;
for(i = 0; i < list_size; i += list[i] + 1)
len += extattr[t].len - 1;
tot_size += list_size + len;
/* Buffer is too small to fit the results */
if(tot_size > size) {
errno = ERANGE;
return -1;
}
/* Shift the results back, so we can prepend prefixes */
buf = memmove(list + len, list, list_size);
for(i = 0; i < list_size; i += len + 1) {
len = buf[i];
strncpy(list, extattr[t].name, extattr[t].len);
strncat(list, buf + i + 1, len);
list += extattr[t].len + len;
}
size -= tot_size;
}
return tot_size;
}
ssize_t sys_listxattr (const char *path, char *list, size_t size)
{
return my_listxattr(0, path, list, size);
}
ssize_t sys_llistxattr (const char *path, char *list, size_t size)
{
return my_listxattr(1, path, list, size);
}
ssize_t sys_flistxattr (int filedes, char *list, size_t size)
{
return my_listxattr(2, &filedes, list, size);
}
int main(int argc, char *argv[]) {
char buf[1024];
ssize_t size;
int fd, i = 0;
//size = sys_listxattr(argv[1], buf, sizeof(buf));
fd = open(argv[1], O_RDONLY);
size = sys_flistxattr(fd, buf, sizeof(buf));
//size = sys_flistxattr(fd, NULL, 0);
printf("Len: %d\n", size);
for(i = 0; i < size; i += strlen(buf+i)+1) {
printf("%s\n", buf+i);
}
return 0;
}
Кстати, не уверен, насколько верно передавать int a в функцию с void* ptr через &a, а потом приводить через *(int*)ptr. Но в теории, размера указателя может не хватить, чтобы поместить в него int(хотя до сих пор работало:)).