ssize_t ceph_os_getxattr(const char *path, const char *name, void *value, size_t size) { ssize_t error = -1; #if defined(__FreeBSD__) if (value == NULL || size == 0) { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, value, size); } else { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, NULL, 0); if (error > 0) { if (error > size) { errno = ERANGE; error = -1; } else { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, value, size); } } } #elif defined(__linux__) error = getxattr(path, name, value, size); #elif defined(DARWIN) error = getxattr(path, name, value, size, 0); #endif return (error); }
ssize_t ceph_os_getxattr(const char *path, const char *name, void *value, size_t size) { ssize_t error = -1; #if defined(__FreeBSD__) if (value == NULL || size == 0) { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, value, size); } else { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, NULL, 0); if (error > 0) { if (error > size) { errno = ERANGE; error = -1; } else { error = extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, value, size); } } } #elif defined(__linux__) error = getxattr(path, name, value, size); #elif defined(DARWIN) error = getxattr(path, name, value, size, 0 /* position */, 0); /* ENOATTR and ENODATA have different values */ if (error < 0 && errno == ENOATTR) errno = ENODATA; #endif return (error); }
ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size) { const char *name = prefix(uname); #if defined(HAVE_GETXATTR) #ifndef XATTR_ADD_OPT return getxattr(path, name, value, size); #else int options = 0; return getxattr(path, name, value, size, 0, options); #endif #elif defined(HAVE_GETEA) return getea(path, name, value, size); #elif defined(HAVE_EXTATTR_GET_FILE) ssize_t retval; /* * The BSD implementation has a nasty habit of silently truncating * the returned value to the size of the buffer, so we have to check * that the buffer is large enough to fit the returned value. */ if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) { if (size == 0) /* size == 0 means only return size */ return retval; if (retval > size) { errno = ERANGE; return -1; } if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0) return retval; } LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)); return -1; #elif defined(HAVE_ATTR_GET) int retval, flags = 0; int valuelength = (int)size; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; retval = attr_get(path, attrname, (char *)value, &valuelength, flags); return retval ? retval : valuelength; #elif defined(HAVE_ATTROPEN) ssize_t ret = -1; int attrfd = solaris_attropen(path, name, O_RDONLY, 0); if (attrfd >= 0) { ret = solaris_read_xattr(attrfd, value, size); close(attrfd); } return ret; #else errno = ENOSYS; return -1; #endif }
ssize_t getAttr( const char* path, const char* attrname, void* data, size_t nbytes ) { ssize_t ret = extattr_get_file( path, EXTATTR_NAMESPACE_USER, attrname, data, nbytes ); checkReturnValue( "getAttr", ret ); return ret; }
static void clear_dosattrib(struct windows_acl_info *w, const char *path) { if (extattr_get_file(path, EXTATTR_NAMESPACE_USER, "DOSATTRIB", NULL, 0) > 0) { if (extattr_delete_file(path, EXTATTR_NAMESPACE_USER, "DOSATTRIB") < 0) warn("%s: extattr_delete_file() failed", path); } }
static int stat_cache_attr_get(buffer *buf, char *name) { ssize_t attrlen; buffer_prepare_copy(buf, 1023); if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, "Content-Type", buf->ptr, buf->size - 1))) { buf->used = attrlen + 1; buf->ptr[attrlen] = '\0'; return 0; } return -1; }
static ssize_t xattr_getxattr(const char *path, const char *name, void *value, ssize_t size, u_int32_t position, int options) { if (position != 0 || !(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { return -1; } if (options & XATTR_XATTR_NOFOLLOW) { return extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size); } else { return extattr_get_file(path, EXTATTR_NAMESPACE_USER, name, value, size); } }
int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags) { const char *name = prefix(uname); #if defined(HAVE_SETXATTR) #ifndef XATTR_ADD_OPT return setxattr(path, name, value, size, flags); #else int options = 0; return setxattr(path, name, value, size, 0, options); #endif #elif defined(HAVE_SETEA) return setea(path, name, value, size, flags); #elif defined(HAVE_EXTATTR_SET_FILE) int retval = 0; if (flags) { /* Check attribute existence */ retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0); if (retval < 0) { /* REPLACE attribute, that doesn't exist */ if (flags & XATTR_REPLACE && errno == ENOATTR) { errno = ENOATTR; return -1; } /* Ignore other errors */ } else { /* CREATE attribute, that already exists */ if (flags & XATTR_CREATE) { errno = EEXIST; return -1; } } } retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size); return (retval < 0) ? -1 : 0; #elif defined(HAVE_ATTR_SET) int myflags = 0; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; return attr_set(path, attrname, (const char *)value, size, myflags); #elif defined(HAVE_ATTROPEN) int ret = -1; int myflags = O_RDWR; int attrfd; if (flags & XATTR_CREATE) myflags |= O_EXCL; if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE); if (attrfd >= 0) { ret = solaris_write_xattr(attrfd, value, size); close(attrfd); } return ret; #else errno = ENOSYS; return -1; #endif }
int main(int argc, char *argv[]) { char *buf, *visbuf, *p; const char *options, *attrname; size_t len; ssize_t ret; int buflen, visbuflen, ch, error, i, arg_counter, attrnamespace, minargc; int flag_force = 0; int flag_nofollow = 0; int flag_null = 0; int flag_quiet = 0; int flag_string = 0; int flag_hex = 0; visbuflen = buflen = 0; visbuf = buf = NULL; p = basename(argv[0]); if (p == NULL) p = argv[0]; if (!strcmp(p, "getextattr")) { what = EAGET; options = "fhqsx"; minargc = 3; } else if (!strcmp(p, "setextattr")) { what = EASET; options = "fhnq"; minargc = 4; } else if (!strcmp(p, "rmextattr")) { what = EARM; options = "fhq"; minargc = 3; } else if (!strcmp(p, "lsextattr")) { what = EALS; options = "fhq"; minargc = 2; } else { usage(); } while ((ch = getopt(argc, argv, options)) != -1) { switch (ch) { case 'f': flag_force = 1; break; case 'h': flag_nofollow = 1; break; case 'n': flag_null = 1; break; case 'q': flag_quiet = 1; break; case 's': flag_string = 1; break; case 'x': flag_hex = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc < minargc) usage(); error = extattr_string_to_namespace(argv[0], &attrnamespace); if (error) err(-1, "%s", argv[0]); argc--; argv++; if (what != EALS) { attrname = argv[0]; argc--; argv++; } else attrname = NULL; if (what == EASET) { mkbuf(&buf, &buflen, strlen(argv[0]) + 1); strcpy(buf, argv[0]); argc--; argv++; } for (arg_counter = 0; arg_counter < argc; arg_counter++) { switch (what) { case EARM: if (flag_nofollow) error = extattr_delete_link(argv[arg_counter], attrnamespace, attrname); else error = extattr_delete_file(argv[arg_counter], attrnamespace, attrname); if (error >= 0) continue; break; case EASET: len = strlen(buf) + flag_null; if (flag_nofollow) ret = extattr_set_link(argv[arg_counter], attrnamespace, attrname, buf, len); else ret = extattr_set_file(argv[arg_counter], attrnamespace, attrname, buf, len); if (ret >= 0) { if ((size_t)ret != len && !flag_quiet) { warnx("Set %zd bytes of %zu for %s", ret, len, attrname); } continue; } break; case EALS: if (flag_nofollow) ret = extattr_list_link(argv[arg_counter], attrnamespace, NULL, 0); else ret = extattr_list_file(argv[arg_counter], attrnamespace, NULL, 0); if (ret < 0) break; mkbuf(&buf, &buflen, ret); if (flag_nofollow) ret = extattr_list_link(argv[arg_counter], attrnamespace, buf, buflen); else ret = extattr_list_file(argv[arg_counter], attrnamespace, buf, buflen); if (ret < 0) break; if (!flag_quiet) printf("%s\t", argv[arg_counter]); for (i = 0; i < ret; i += ch + 1) { /* The attribute name length is unsigned. */ ch = (unsigned char)buf[i]; printf("%s%*.*s", i ? "\t" : "", ch, ch, buf + i + 1); } if (!flag_quiet || ret > 0) printf("\n"); continue; case EAGET: if (flag_nofollow) ret = extattr_get_link(argv[arg_counter], attrnamespace, attrname, NULL, 0); else ret = extattr_get_file(argv[arg_counter], attrnamespace, attrname, NULL, 0); if (ret < 0) break; mkbuf(&buf, &buflen, ret); if (flag_nofollow) ret = extattr_get_link(argv[arg_counter], attrnamespace, attrname, buf, buflen); else ret = extattr_get_file(argv[arg_counter], attrnamespace, attrname, buf, buflen); if (ret < 0) break; if (!flag_quiet) printf("%s\t", argv[arg_counter]); if (flag_string) { mkbuf(&visbuf, &visbuflen, ret * 4 + 1); strvisx(visbuf, buf, ret, VIS_SAFE | VIS_WHITE); printf("\"%s\"\n", visbuf); continue; } else if (flag_hex) { for (i = 0; i < ret; i++) printf("%s%02x", i ? " " : "", buf[i]); printf("\n"); continue; } else { fwrite(buf, ret, 1, stdout); printf("\n"); continue; } default: break; } if (!flag_quiet) warn("%s: failed", argv[arg_counter]); if (flag_force) continue; return(1); } return (0); }
static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) { DIR *dp; buffer *out; struct dirent *dent; struct stat st; char *path, *path_file; size_t i; int hide_dotfiles = p->conf.hide_dot_files; dirls_list_t dirs, files, *list; dirls_entry_t *tmp; char sizebuf[sizeof("999.9K")]; char datebuf[sizeof("2005-Jan-01 22:23:24")]; size_t k; const char *content_type; long name_max; #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) char attrval[128]; int attrlen; #endif #ifdef HAVE_LOCALTIME_R struct tm tm; #endif if (buffer_string_is_empty(dir)) return -1; i = buffer_string_length(dir); #ifdef HAVE_PATHCONF if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) { /* some broken fs (fuse) return 0 instead of -1 */ #ifdef NAME_MAX name_max = NAME_MAX; #else name_max = 255; /* stupid default */ #endif } #elif defined __WIN32 name_max = FILENAME_MAX; #else name_max = NAME_MAX; #endif path = malloc(i + name_max + 1); force_assert(NULL != path); memcpy(path, dir->ptr, i+1); path_file = path + i; if (NULL == (dp = opendir(path))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opendir failed:", dir, strerror(errno)); free(path); return -1; } dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE); force_assert(dirs.ent); dirs.size = DIRLIST_BLOB_SIZE; dirs.used = 0; files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE); force_assert(files.ent); files.size = DIRLIST_BLOB_SIZE; files.used = 0; while ((dent = readdir(dp)) != NULL) { unsigned short exclude_match = 0; if (dent->d_name[0] == '.') { if (hide_dotfiles) continue; if (dent->d_name[1] == '\0') continue; if (dent->d_name[1] == '.' && dent->d_name[2] == '\0') continue; } if (p->conf.hide_readme_file && !buffer_string_is_empty(p->conf.show_readme)) { if (strcmp(dent->d_name, p->conf.show_readme->ptr) == 0) continue; } if (p->conf.hide_header_file && !buffer_string_is_empty(p->conf.show_header)) { if (strcmp(dent->d_name, p->conf.show_header->ptr) == 0) continue; } /* compare d_name against excludes array * elements, skipping any that match. */ #ifdef HAVE_PCRE_H for(i = 0; i < p->conf.excludes->used; i++) { int n; #define N 10 int ovec[N * 3]; pcre *regex = p->conf.excludes->ptr[i]->regex; if ((n = pcre_exec(regex, NULL, dent->d_name, strlen(dent->d_name), 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { log_error_write(srv, __FILE__, __LINE__, "sd", "execution error while matching:", n); /* aborting would require a lot of manual cleanup here. * skip instead (to not leak names that break pcre matching) */ exclude_match = 1; break; } } else { exclude_match = 1; break; } } if (exclude_match) { continue; } #endif i = strlen(dent->d_name); /* NOTE: the manual says, d_name is never more than NAME_MAX * so this should actually not be a buffer-overflow-risk */ if (i > (size_t)name_max) continue; memcpy(path_file, dent->d_name, i + 1); if (stat(path, &st) != 0) continue; list = &files; if (S_ISDIR(st.st_mode)) list = &dirs; if (list->used == list->size) { list->size += DIRLIST_BLOB_SIZE; list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size); force_assert(list->ent); } tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i); tmp->mtime = st.st_mtime; tmp->size = st.st_size; tmp->namelen = i; memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1); list->ent[list->used++] = tmp; } closedir(dp); if (dirs.used) http_dirls_sort(dirs.ent, dirs.used); if (files.used) http_dirls_sort(files.ent, files.used); out = buffer_init(); http_list_directory_header(srv, con, p, out); /* directories */ for (i = 0; i < dirs.used; i++) { tmp = dirs.ent[i]; #ifdef HAVE_LOCALTIME_R localtime_r(&(tmp->mtime), &tm); strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); #else strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime))); #endif buffer_append_string_len(out, CONST_STR_LEN("<tr class=\"d\"><td class=\"n\"><a href=\"")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART); buffer_append_string_len(out, CONST_STR_LEN("/\">")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</a>/</td><td class=\"m\">")); buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1); buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">- </td><td class=\"t\">Directory</td></tr>\n")); free(tmp); } /* files */ for (i = 0; i < files.used; i++) { tmp = files.ent[i]; content_type = NULL; #if defined(HAVE_XATTR) if (con->conf.use_xattr) { memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1); attrlen = sizeof(attrval) - 1; if (attr_get(path, srv->srvconf.xattr_name->ptr, attrval, &attrlen, 0) == 0) { attrval[attrlen] = '\0'; content_type = attrval; } } #elif defined(HAVE_EXTATTR) if (con->conf.use_xattr) { memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1); if(-1 != (attrlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, srv->srvconf.xattr_name->ptr, attrval, sizeof(attrval)-1))) { attrval[attrlen] = '\0'; content_type = attrval; } } #endif if (content_type == NULL) { content_type = "application/octet-stream"; for (k = 0; k < con->conf.mimetypes->used; k++) { data_string *ds = (data_string *)con->conf.mimetypes->data[k]; size_t ct_len; if (buffer_is_empty(ds->key)) continue; ct_len = buffer_string_length(ds->key); if (tmp->namelen < ct_len) continue; if (0 == strncasecmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) { content_type = ds->value->ptr; break; } } } #ifdef HAVE_LOCALTIME_R localtime_r(&(tmp->mtime), &tm); strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); #else strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime))); #endif http_list_directory_sizefmt(sizebuf, sizeof(sizebuf), tmp->size); buffer_append_string_len(out, CONST_STR_LEN("<tr><td class=\"n\"><a href=\"")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART); buffer_append_string_len(out, CONST_STR_LEN("\">")); buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</a></td><td class=\"m\">")); buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1); buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">")); buffer_append_string(out, sizebuf); buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"t\">")); buffer_append_string(out, content_type); buffer_append_string_len(out, CONST_STR_LEN("</td></tr>\n")); free(tmp); } free(files.ent); free(dirs.ent); free(path); http_list_directory_footer(srv, con, p, out); /* Insert possible charset to Content-Type */ if (buffer_string_is_empty(p->conf.encoding)) { response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); } else { buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset=")); buffer_append_string_buffer(p->content_charset, p->conf.encoding); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset)); } con->file_finished = 1; chunkqueue_append_buffer(con->write_queue, out); buffer_free(out); return 0; }
/* Obtain the Extended Attributes and/or the ACLs of the given file in a form that is ready for aaip_encode(). @param path Path to the file @param num_attrs Will return the number of name-value pairs @param names Will return an array of pointers to 0-terminated names @param value_lengths Will return an arry with the lenghts of values @param values Will return an array of pointers to 8-bit values @param flag Bitfield for control purposes bit0= obtain ACL (access and eventually default) bit1= use numeric ACL qualifiers rather than names bit2= do not obtain attributes other than ACL bit3= do not ignore eventual non-user attributes I.e. those with a name which does not begin by "user." bit4= do not return trivial ACL that matches st_mode bit5= in case of symbolic link: inquire link target bit15= free memory of names, value_lengths, values @return >0 ok <=0 error -1= out of memory -2= program error with prediction of result size -3= error with conversion of name to uid or gid */ int aaip_get_attr_list(char *path, size_t *num_attrs, char ***names, size_t **value_lengths, char ***values, int flag) { int ret; ssize_t i, num_names= 0, acl_names= 0; #ifdef Libisofs_with_aaip_acL unsigned char *a_acl= NULL; char *a_acl_text= NULL; size_t a_acl_len= 0; #endif #ifdef Libisofs_with_freebsd_extattR char *list= NULL, *user_list= NULL, *sys_list= NULL, *namept; ssize_t value_ret, retry= 0, list_size= 0, user_list_size= 0; ssize_t sys_list_size= 0; int attrnamespace; #endif if(flag & (1 << 15)) { /* Free memory */ {ret= 1; goto ex;} } *num_attrs= 0; *names= NULL; *value_lengths= NULL; *values= NULL; /* Set up arrays */ #ifdef Libisofs_with_freebsd_extattR if(!(flag & 4)) { /* Get extattr names */ /* Linux : Names are encoded as name NUL FreeBSD: Names are encoded as length_byte:chars (no NUL) AAIP demands names not to contain NUL bytes. */ /* Obtain lists of names Must be done separately for namespaces. See man 9 extattr : EXTATTR_NAMESPACE_USER , EXTATTR_NAMESPACE_SYSTEM Must then be marked by "user." and "system." for libisofs use. */ ret= aaip_extattr_make_list(path, EXTATTR_NAMESPACE_USER, &user_list, &user_list_size, flag & 32); if(ret <= 0) {ret= -1; goto ex;} if(flag & 8) { ret= aaip_extattr_make_list(path, EXTATTR_NAMESPACE_SYSTEM, &sys_list, &sys_list_size, flag & 32); if(ret <= 0) {ret= -1; goto ex;} } /* Check for NUL in names, convert into a linuxish list of namespace.name */ ret= aaip_extattr_make_namelist(path, "user", user_list, user_list_size, &list, &list_size, &num_names, 0); if(ret <= 0) goto ex; ret= aaip_extattr_make_namelist(path, "system", sys_list, sys_list_size, &list, &list_size, &num_names, 1); if(ret <= 0) goto ex; } #endif /* Libisofs_with_freebsd_extattR */ #ifdef Libisofs_with_aaip_acL if(flag & 1) { num_names++; acl_names= 1; } #endif if(num_names == 0) {ret= 1; goto ex;} (*names)= calloc(num_names, sizeof(char *)); (*value_lengths)= calloc(num_names, sizeof(size_t)); (*values)= calloc(num_names, sizeof(char *)); if(*names == NULL || *value_lengths == NULL || *values == NULL) {ret= -1; goto ex;} for(i= 0; i < num_names; i++) { (*names)[i]= NULL; (*values)[i]= NULL; (*value_lengths)[i]= 0; } #ifdef Libisofs_with_freebsd_extattR if(!(flag & 4)) { /* Get xattr values */ for(i= 0; i < list_size && (size_t) num_names - acl_names > *num_attrs; i+= strlen(list + i) + 1) { if(!(flag & 8)) if(strncmp(list + i, "user.", 5)) continue; (*names)[(*num_attrs)++]= strdup(list + i); if((*names)[(*num_attrs) - 1] == NULL) {ret= -1; goto ex;} } for(i= 0; (size_t) i < *num_attrs; i++) { if(strncmp((*names)[i], "user.", 5) == 0) { attrnamespace= EXTATTR_NAMESPACE_USER; namept= (*names)[i] + 5; } else { if(!(flag & 8)) continue; attrnamespace= EXTATTR_NAMESPACE_SYSTEM; namept= (*names)[i] + 7; } /* Predict length of value */ if(flag & 32) /* follow link */ value_ret= extattr_get_file(path, attrnamespace, namept, NULL, (size_t) 0); else value_ret= extattr_get_link(path, attrnamespace, namept, NULL, (size_t) 0); if(value_ret == -1) continue; (*values)[i]= calloc(value_ret + 1, 1); if((*values)[i] == NULL) {ret= -1; goto ex;} /* Obtain value */ if(flag & 32) /* follow link */ value_ret= extattr_get_file(path, attrnamespace, namept, (*values)[i], (size_t) value_ret); else value_ret= extattr_get_link(path, attrnamespace, namept, (*values)[i], (size_t) value_ret); if(value_ret == -1) { /* there could be a race condition */ if(retry++ > 5) {ret= -1; goto ex;} i--; continue; } (*value_lengths)[i]= value_ret; retry= 0; } } #endif /* Libisofs_with_freebsd_extattR */ #ifdef Libisofs_with_aaip_acL if(flag & 1) { /* Obtain ACL */ /* access-ACL */ aaip_get_acl_text(path, &a_acl_text, flag & (16 | 32)); if(a_acl_text == NULL) {ret= 1; goto ex;} /* empty ACL / only st_mode info was found in ACL */ ret= aaip_encode_acl(a_acl_text, (mode_t) 0, &a_acl_len, &a_acl, flag & 2); if(ret <= 0) goto ex; /* Note: There are no default-ACL in FreeBSD */ /* Set as attribute with empty name */; (*names)[*num_attrs]= strdup(""); if((*names)[*num_attrs] == NULL) {ret= -1; goto ex;} (*values)[*num_attrs]= (char *) a_acl; a_acl= NULL; (*value_lengths)[*num_attrs]= a_acl_len; (*num_attrs)++; } #endif /* Libisofs_with_aaip_acL */ ret= 1; ex:; #ifdef Libisofs_with_aaip_acL if(a_acl != NULL) free(a_acl); if(a_acl_text != NULL) aaip_get_acl_text("", &a_acl_text, 1 << 15); /* free */ #endif #ifdef Libisofs_with_freebsd_extattR if(list != NULL) free(list); if(user_list != NULL) free(user_list); if(sys_list != NULL) free(sys_list); #endif if(ret <= 0 || (flag & (1 << 15))) { if(*names != NULL) { for(i= 0; (size_t) i < *num_attrs; i++) free((*names)[i]); free(*names); } *names= NULL; if(*value_lengths != NULL) free(*value_lengths); *value_lengths= NULL; if(*values != NULL) { for(i= 0; (size_t) i < *num_attrs; i++) free((*values)[i]); free(*values); } *values= NULL; *num_attrs= 0; } return(ret); }
/* * This program displays the location information of a data storage file * for a given file on a MetaData Server (MDS) in a pNFS service. This program * must be run on the MDS and the file argument must be a file in a local * file system that has been exported for the pNFS service. */ int main(int argc, char *argv[]) { struct addrinfo *res, *ad, *newres; struct sockaddr_in *sin, adsin; struct sockaddr_in6 *sin6, adsin6; char hostn[2 * NI_MAXHOST + 2], *cp; struct pnfsdsfile dsfile[NFSDEV_MAXMIRRORS]; int ch, dosetxattr, i, mirrorcnt, mirrorit, quiet, zerods, zerofh; in_port_t tport; ssize_t xattrsize, xattrsize2; zerods = 0; zerofh = 0; mirrorit = 0; quiet = 0; dosetxattr = 0; res = NULL; newres = NULL; cp = NULL; while ((ch = getopt_long(argc, argv, "c:m:qr:s:z", longopts, NULL)) != -1) { switch (ch) { case 'c': /* Replace the first DS server with the second one. */ if (zerofh != 0 || zerods != 0 || mirrorit != 0 || newres != NULL || res != NULL) errx(1, "-c, -m, -r, -s and -z are mutually " "exclusive and only can be used once"); strlcpy(hostn, optarg, 2 * NI_MAXHOST + 2); cp = strchr(hostn, ','); if (cp == NULL) errx(1, "Bad -c argument %s", hostn); *cp = '\0'; if (getaddrinfo(hostn, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s", hostn); *cp++ = ','; if (getaddrinfo(cp, NULL, NULL, &newres) != 0) errx(1, "Can't get IP# for %s", cp); break; case 'm': /* Add 0.0.0.0 entries up to mirror level. */ if (zerofh != 0 || zerods != 0 || mirrorit != 0 || newres != NULL || res != NULL) errx(1, "-c, -m, -r, -s and -z are mutually " "exclusive and only can be used once"); mirrorit = atoi(optarg); if (mirrorit < 2 || mirrorit > NFSDEV_MAXMIRRORS) errx(1, "-m %d out of range", mirrorit); break; case 'q': quiet = 1; break; case 'r': /* Reset the DS server in a mirror with 0.0.0.0. */ if (zerofh != 0 || zerods != 0 || mirrorit != 0 || newres != NULL || res != NULL) errx(1, "-c, -m, -r, -s and -z are mutually " "exclusive and only can be used once"); zerods = 1; /* Translate the server name to an IP address. */ if (getaddrinfo(optarg, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s", optarg); break; case 's': /* Translate the server name to an IP address. */ if (zerods != 0 || mirrorit != 0 || newres != NULL || res != NULL) errx(1, "-c, -m and -r are mutually exclusive " "from use with -s and -z"); if (getaddrinfo(optarg, NULL, NULL, &res) != 0) errx(1, "Can't get IP# for %s", optarg); break; case 'z': if (zerofh != 0 || zerods != 0 || mirrorit != 0 || newres != NULL) errx(1, "-c, -m and -r are mutually exclusive " "from use with -s and -z"); zerofh = 1; break; default: usage(); } } argc -= optind; if (argc != 1) usage(); argv += optind; /* * The host address and directory where the data storage file is * located is in the extended attribute "pnfsd.dsfile". */ xattrsize = extattr_get_file(*argv, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", dsfile, sizeof(dsfile)); mirrorcnt = xattrsize / sizeof(struct pnfsdsfile); xattrsize2 = mirrorcnt * sizeof(struct pnfsdsfile); if (mirrorcnt < 1 || xattrsize != xattrsize2) err(1, "Can't get extattr pnfsd.dsfile for %s", *argv); if (quiet == 0) printf("%s:\t", *argv); for (i = 0; i < mirrorcnt; i++) { if (i > 0 && quiet == 0) printf("\t"); /* Do the zerofh option. You must be root. */ if (zerofh != 0) { if (geteuid() != 0) errx(1, "Must be root/su to zerofh"); /* * Do it for the server specified by -s/--ds or all * servers, if -s/--ds was not specified. */ sin = &dsfile[i].dsf_sin; sin6 = &dsfile[i].dsf_sin6; ad = res; while (ad != NULL) { if (ad->ai_addr->sa_family == AF_INET && sin->sin_family == AF_INET && ad->ai_addrlen >= sizeof(adsin)) { memcpy(&adsin, ad->ai_addr, sizeof(adsin)); if (sin->sin_addr.s_addr == adsin.sin_addr.s_addr) break; } if (ad->ai_addr->sa_family == AF_INET6 && sin6->sin6_family == AF_INET6 && ad->ai_addrlen >= sizeof(adsin6)) { memcpy(&adsin6, ad->ai_addr, sizeof(adsin6)); if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &adsin6.sin6_addr)) break; } ad = ad->ai_next; } if (res == NULL || ad != NULL) { memset(&dsfile[i].dsf_fh, 0, sizeof(fhandle_t)); dosetxattr = 1; } } /* Do the zerods option. You must be root. */ if (zerods != 0 && mirrorcnt > 1) { if (geteuid() != 0) errx(1, "Must be root/su to zerods"); /* * Do it for the server specified. */ sin = &dsfile[i].dsf_sin; sin6 = &dsfile[i].dsf_sin6; ad = res; while (ad != NULL) { if (ad->ai_addr->sa_family == AF_INET && sin->sin_family == AF_INET && ad->ai_addrlen >= sizeof(adsin)) { memcpy(&adsin, ad->ai_addr, sizeof(adsin)); if (sin->sin_addr.s_addr == adsin.sin_addr.s_addr) break; } if (ad->ai_addr->sa_family == AF_INET6 && sin6->sin6_family == AF_INET6 && ad->ai_addrlen >= sizeof(adsin6)) { memcpy(&adsin6, ad->ai_addr, sizeof(adsin6)); if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &adsin6.sin6_addr)) break; } ad = ad->ai_next; } if (ad != NULL) { sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_port = 0; sin->sin_addr.s_addr = 0; dosetxattr = 1; } } /* Do the -c option to replace the DS host address. */ if (newres != NULL) { if (geteuid() != 0) errx(1, "Must be root/su to replace the host" " addr"); /* * Check that the old host address matches. */ sin = &dsfile[i].dsf_sin; sin6 = &dsfile[i].dsf_sin6; ad = res; while (ad != NULL) { if (ad->ai_addr->sa_family == AF_INET && sin->sin_family == AF_INET && ad->ai_addrlen >= sizeof(adsin)) { memcpy(&adsin, ad->ai_addr, sizeof(adsin)); if (sin->sin_addr.s_addr == adsin.sin_addr.s_addr) break; } if (ad->ai_addr->sa_family == AF_INET6 && sin6->sin6_family == AF_INET6 && ad->ai_addrlen >= sizeof(adsin6)) { memcpy(&adsin6, ad->ai_addr, sizeof(adsin6)); if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &adsin6.sin6_addr)) break; } ad = ad->ai_next; } if (ad != NULL) { if (sin->sin_family == AF_INET) tport = sin->sin_port; else tport = sin6->sin6_port; /* * We have a match, so replace it with the first * AF_INET or AF_INET6 address in the newres * list. */ while (newres->ai_addr->sa_family != AF_INET && newres->ai_addr->sa_family != AF_INET6) { newres = newres->ai_next; if (newres == NULL) errx(1, "Hostname %s has no" " IP#", cp); } if (newres->ai_addr->sa_family == AF_INET) { memcpy(sin, newres->ai_addr, sizeof(*sin)); sin->sin_port = tport; } else if (newres->ai_addr->sa_family == AF_INET6) { memcpy(sin6, newres->ai_addr, sizeof(*sin6)); sin6->sin6_port = tport; } dosetxattr = 1; } } if (quiet == 0) { /* Translate the IP address to a hostname. */ if (getnameinfo((struct sockaddr *)&dsfile[i].dsf_sin, dsfile[i].dsf_sin.sin_len, hostn, sizeof(hostn), NULL, 0, 0) < 0) err(1, "Can't get hostname"); printf("%s\tds%d/%s", hostn, dsfile[i].dsf_dir, dsfile[i].dsf_filename); } } /* Add entrie(s) with IP address set to 0.0.0.0, as required. */ for (i = mirrorcnt; i < mirrorit; i++) { dsfile[i] = dsfile[0]; dsfile[i].dsf_sin.sin_family = AF_INET; dsfile[i].dsf_sin.sin_len = sizeof(struct sockaddr_in); dsfile[i].dsf_sin.sin_addr.s_addr = 0; dsfile[i].dsf_sin.sin_port = 0; if (quiet == 0) { /* Print out the 0.0.0.0 entry. */ printf("\t0.0.0.0\tds%d/%s", dsfile[i].dsf_dir, dsfile[i].dsf_filename); } } if (mirrorit > mirrorcnt) { xattrsize = mirrorit * sizeof(struct pnfsdsfile); dosetxattr = 1; } if (quiet == 0) printf("\n"); if (dosetxattr != 0 && extattr_set_file(*argv, EXTATTR_NAMESPACE_SYSTEM, "pnfsd.dsfile", dsfile, xattrsize) != xattrsize) err(1, "Can't set pnfsd.dsfile"); }
ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size) { #if defined(HAVE_GETXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return getxattr(path, name, value, size); #else /* So that we do not recursivly call this function */ #undef getxattr int options = 0; return getxattr(path, name, value, size, 0, options); #endif #elif defined(HAVE_GETEA) return getea(path, name, value, size); #elif defined(HAVE_EXTATTR_GET_FILE) char *s; ssize_t retval; int attrnamespace = (strncmp(name, "system", 6) == 0) ? EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1; /* * The BSD implementation has a nasty habit of silently truncating * the returned value to the size of the buffer, so we have to check * that the buffer is large enough to fit the returned value. */ if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) { if (size == 0) { return retval; } else if (retval > size) { errno = ERANGE; return -1; } if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0) return retval; } return -1; #elif defined(HAVE_ATTR_GET) int retval, flags = 0; int valuelength = (int)size; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; retval = attr_get(path, attrname, (char *)value, &valuelength, flags); if (size == 0 && retval == -1 && errno == E2BIG) { return valuelength; } return retval ? retval : valuelength; #elif defined(HAVE_ATTROPEN) ssize_t ret = -1; int attrfd = solaris_attropen(path, name, O_RDONLY, 0); if (attrfd >= 0) { ret = solaris_read_xattr(attrfd, value, size); close(attrfd); } return ret; #else errno = ENOSYS; return -1; #endif }