CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
xattr.cc
Go to the documentation of this file.
1 
6 #include "xattr.h"
7 
8 #include <alloca.h>
9 // clang-format off
10 #include <sys/xattr.h>
11 // clang-format on
12 
13 #include <cassert>
14 #include <cstring>
15 
16 #include "util/platform.h"
17 #include "util/pointer.h"
18 #include "util/smalloc.h"
19 #include "util/string.h"
20 
21 using namespace std; // NOLINT
22 
23 const uint8_t XattrList::kVersion = 1;
24 
32 XattrList *XattrList::CreateFromFile(const std::string &path) {
33  // Parse the \0 separated list of extended attribute keys
34  char *list;
35  ssize_t sz_list = platform_llistxattr(path.c_str(), NULL, 0);
36  if ((sz_list < 0) || (sz_list > 64 * 1024)) {
37  return NULL;
38  } else if (sz_list == 0) {
39  // No extended attributes
40  return new XattrList();
41  }
42  list = reinterpret_cast<char *>(alloca(sz_list));
43  sz_list = platform_llistxattr(path.c_str(), list, sz_list);
44  if (sz_list < 0) {
45  return NULL;
46  } else if (sz_list == 0) {
47  // Can only happen if the list was removed since the previous call to
48  // llistxattr
49  return new XattrList();
50  }
51  vector<string> keys = SplitString(string(list, sz_list), '\0');
52 
53  // Retrieve extended attribute values
54  XattrList *result = new XattrList();
55  char value[256];
56  for (unsigned i = 0; i < keys.size(); ++i) {
57  if (keys[i].empty())
58  continue;
59  ssize_t sz_value = platform_lgetxattr(path.c_str(), keys[i].c_str(), value,
60  256);
61  if (sz_value < 0)
62  continue;
63  result->Set(keys[i], string(value, sz_value));
64  }
65  return result;
66 }
67 
68 
69 XattrList *XattrList::Deserialize(const unsigned char *inbuf,
70  const unsigned size) {
71  if (inbuf == NULL)
72  return new XattrList();
73 
74  UniquePtr<XattrList> result(new XattrList());
75  if (size < sizeof(XattrHeader))
76  return NULL;
77  XattrHeader header;
78  memcpy(&header, inbuf, sizeof(header));
79  if (header.version != kVersion)
80  return NULL;
81  unsigned pos = sizeof(header);
82  for (unsigned i = 0; i < header.num_xattrs; ++i) {
83  XattrEntry entry;
84  unsigned size_preamble = sizeof(entry.len_key) + sizeof(entry.len_value);
85  if (size - pos < size_preamble)
86  return NULL;
87  memcpy(&entry, inbuf + pos, size_preamble);
88  if (size - pos < entry.GetSize())
89  return NULL;
90  if (entry.GetSize() == size_preamble)
91  return NULL;
92  pos += size_preamble;
93  memcpy(entry.data, inbuf + pos, entry.GetSize() - size_preamble);
94  pos += entry.GetSize() - size_preamble;
95  bool retval = result->Set(entry.GetKey(), entry.GetValue());
96  if (!retval)
97  return NULL;
98  }
99  return result.Release();
100 }
101 
102 
103 bool XattrList::Has(const string &key) const {
104  return xattrs_.find(key) != xattrs_.end();
105 }
106 
107 
108 bool XattrList::Get(const string &key, string *value) const {
109  assert(value);
110  map<string, string>::const_iterator iter = xattrs_.find(key);
111  if (iter != xattrs_.end()) {
112  *value = iter->second;
113  return true;
114  }
115  return false;
116 }
117 
118 
119 vector<string> XattrList::ListKeys() const {
120  vector<string> result;
121  for (map<string, string>::const_iterator i = xattrs_.begin(),
122  iEnd = xattrs_.end();
123  i != iEnd;
124  ++i) {
125  result.push_back(i->first);
126  }
127  return result;
128 }
129 
130 
138 string XattrList::ListKeysPosix(const string &merge_with) const {
139  string result;
140  if (!merge_with.empty()) {
141  vector<string> merge_list = SplitString(merge_with, '\0');
142  for (unsigned i = 0; i < merge_list.size(); ++i) {
143  if (merge_list[i].empty())
144  continue;
145  if (xattrs_.find(merge_list[i]) == xattrs_.end()) {
146  result += merge_list[i];
147  result.push_back('\0');
148  }
149  }
150  }
151  for (map<string, string>::const_iterator i = xattrs_.begin(),
152  iEnd = xattrs_.end();
153  i != iEnd;
154  ++i) {
155  result += i->first;
156  result.push_back('\0');
157  }
158  return result;
159 }
160 
161 
162 bool XattrList::Set(const string &key, const string &value) {
163  if (key.empty())
164  return false;
165  if (key.length() > 256)
166  return false;
167  if (key.find('\0') != string::npos)
168  return false;
169  if (value.length() > 256)
170  return false;
171 
172  map<string, string>::iterator iter = xattrs_.find(key);
173  if (iter != xattrs_.end()) {
174  iter->second = value;
175  } else {
176  if (xattrs_.size() >= 256)
177  return false;
178  xattrs_[key] = value;
179  }
180  return true;
181 }
182 
183 
184 bool XattrList::Remove(const string &key) {
185  map<string, string>::iterator iter = xattrs_.find(key);
186  if (iter != xattrs_.end()) {
187  xattrs_.erase(iter);
188  return true;
189  }
190  return false;
191 }
192 
193 
198 void XattrList::Serialize(unsigned char **outbuf,
199  unsigned *size,
200  const std::vector<std::string> *blacklist) const {
201  if (xattrs_.empty()) {
202  *size = 0;
203  *outbuf = NULL;
204  return;
205  }
206 
207  XattrHeader header(xattrs_.size());
208  uint32_t packed_size = sizeof(header);
209 
210  // Determine size of the buffer (allocate space for max num of attributes)
211  XattrEntry *entries = reinterpret_cast<XattrEntry *>(
212  smalloc(header.num_xattrs * sizeof(XattrEntry)));
213  unsigned ientries = 0;
214  for (map<string, string>::const_iterator it_att = xattrs_.begin(),
215  it_att_end = xattrs_.end();
216  it_att != it_att_end;
217  ++it_att) {
218  // Only serialize non-blacklist items
219  if (blacklist != NULL) {
220  bool skip = false;
221  for (unsigned i_bl = 0; i_bl < blacklist->size(); ++i_bl) {
222  if (HasPrefix(it_att->first, (*blacklist)[i_bl],
223  true /* ignore_case */)) {
224  skip = true;
225  break;
226  }
227  }
228  if (skip)
229  continue;
230  }
231  /*entries[ientries] =*/
232  new (entries + ientries) XattrEntry(it_att->first, it_att->second);
233  packed_size += entries[ientries].GetSize();
234  ientries++;
235  }
236 
237  // We might have skipped all attributes
238  if (ientries == 0) {
239  free(entries);
240  *size = 0;
241  *outbuf = NULL;
242  return;
243  }
244 
245  // Copy data into buffer
246  header.num_xattrs = ientries;
247  *size = packed_size;
248  *outbuf = reinterpret_cast<unsigned char *>(smalloc(packed_size));
249  memcpy(*outbuf, &header, sizeof(header));
250  unsigned pos = sizeof(header);
251  for (unsigned i = 0; i < header.num_xattrs; ++i) {
252  memcpy(*outbuf + pos, &entries[i], entries[i].GetSize());
253  pos += entries[i].GetSize();
254  }
255 
256  free(entries);
257 }
258 
259 
260 //------------------------------------------------------------------------------
261 
262 
264  if (len_key == 0)
265  return "";
266  return string(data, len_key);
267 }
268 
269 
271  return sizeof(len_key) + sizeof(len_value) + uint16_t(len_key)
272  + uint16_t(len_value);
273 }
274 
275 
277  if (len_value == 0)
278  return "";
279  return string(&data[len_key], len_value);
280 }
281 
282 
283 XattrList::XattrEntry::XattrEntry(const string &key, const string &value)
284  : len_key(key.size()), len_value(value.size()) {
285  memcpy(data, key.data(), len_key);
286  memcpy(data + len_key, value.data(), len_value);
287 }
std::string ListKeysPosix(const std::string &merge_with) const
Definition: xattr.cc:138
char data[512]
Definition: xattr.h:68
bool Set(const std::string &key, const std::string &value)
Definition: xattr.cc:162
assert((mem||(size==0))&&"Out Of Memory")
uint16_t GetSize() const
Definition: xattr.cc:270
ssize_t platform_llistxattr(const char *path, char *list, size_t size)
bool Get(const std::string &key, std::string *value) const
Definition: xattr.cc:108
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:306
std::string GetValue() const
Definition: xattr.cc:276
void Serialize(unsigned char **outbuf, unsigned *size, const std::vector< std::string > *blacklist=NULL) const
Definition: xattr.cc:198
ssize_t platform_lgetxattr(const char *path, const char *name, void *value, size_t size)
Definition: xattr.h:58
bool Has(const std::string &key) const
Definition: xattr.cc:103
std::string GetKey() const
Definition: xattr.cc:263
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:279
static XattrList * Deserialize(const unsigned char *inbuf, const unsigned size)
Definition: xattr.cc:69
uint8_t len_key
Definition: xattr.h:64
static XattrList * CreateFromFile(const std::string &path)
Definition: xattr.cc:32
static const uint8_t kVersion
Definition: xattr.h:29
uint8_t num_xattrs
Definition: xattr.h:56
const char * kVersion
Definition: preload.cc:26
std::vector< std::string > ListKeys() const
Definition: xattr.cc:119
XattrEntry()
Definition: xattr.h:60
uint8_t len_value
Definition: xattr.h:65
static void size_t size
Definition: smalloc.h:54
bool Remove(const std::string &key)
Definition: xattr.cc:184