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  const ssize_t sz_value =
60  platform_lgetxattr(path.c_str(), keys[i].c_str(), value, 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 = //NOLINT
85  sizeof(entry.len_key) + sizeof(entry.len_value);
86  if (size - pos < size_preamble)
87  return NULL;
88  memcpy(&entry, inbuf + pos, size_preamble);
89  if (size - pos < entry.GetSize())
90  return NULL;
91  if (entry.GetSize() == size_preamble)
92  return NULL;
93  pos += size_preamble;
94  memcpy(entry.data, inbuf + pos, entry.GetSize() - size_preamble);
95  pos += entry.GetSize() - size_preamble;
96  const bool retval = result->Set(entry.GetKey(), entry.GetValue());
97  if (!retval)
98  return NULL;
99  }
100  return result.Release();
101 }
102 
103 
104 bool XattrList::Has(const string &key) const {
105  return xattrs_.find(key) != xattrs_.end();
106 }
107 
108 
109 bool XattrList::Get(const string &key, string *value) const {
110  assert(value);
111  const map<string, string>::const_iterator iter = xattrs_.find(key);
112  if (iter != xattrs_.end()) {
113  *value = iter->second;
114  return true;
115  }
116  return false;
117 }
118 
119 
120 vector<string> XattrList::ListKeys() const {
121  vector<string> result;
122  for (map<string, string>::const_iterator i = xattrs_.begin(),
123  iEnd = xattrs_.end();
124  i != iEnd;
125  ++i) {
126  result.push_back(i->first);
127  }
128  return result;
129 }
130 
131 
139 string XattrList::ListKeysPosix(const string &merge_with) const {
140  string result;
141  if (!merge_with.empty()) {
142  vector<string> merge_list = SplitString(merge_with, '\0');
143  for (unsigned i = 0; i < merge_list.size(); ++i) {
144  if (merge_list[i].empty())
145  continue;
146  if (xattrs_.find(merge_list[i]) == xattrs_.end()) {
147  result += merge_list[i];
148  result.push_back('\0');
149  }
150  }
151  }
152  for (map<string, string>::const_iterator i = xattrs_.begin(),
153  iEnd = xattrs_.end();
154  i != iEnd;
155  ++i) {
156  result += i->first;
157  result.push_back('\0');
158  }
159  return result;
160 }
161 
162 
163 bool XattrList::Set(const string &key, const string &value) {
164  if (key.empty())
165  return false;
166  if (key.length() > 256)
167  return false;
168  if (key.find('\0') != string::npos)
169  return false;
170  if (value.length() > 256)
171  return false;
172 
173  const map<string, string>::iterator iter = xattrs_.find(key);
174  if (iter != xattrs_.end()) {
175  iter->second = value;
176  } else {
177  if (xattrs_.size() >= 256)
178  return false;
179  xattrs_[key] = value;
180  }
181  return true;
182 }
183 
184 
185 bool XattrList::Remove(const string &key) {
186  const map<string, string>::iterator iter = xattrs_.find(key);
187  if (iter != xattrs_.end()) {
188  xattrs_.erase(iter);
189  return true;
190  }
191  return false;
192 }
193 
194 
199 void XattrList::Serialize(unsigned char **outbuf,
200  unsigned *size,
201  const std::vector<std::string> *blacklist) const {
202  if (xattrs_.empty()) {
203  *size = 0;
204  *outbuf = NULL;
205  return;
206  }
207 
208  XattrHeader header(xattrs_.size());
209  uint32_t packed_size = sizeof(header);
210 
211  // Determine size of the buffer (allocate space for max num of attributes)
212  XattrEntry *entries = reinterpret_cast<XattrEntry *>(
213  smalloc(header.num_xattrs * sizeof(XattrEntry)));
214  unsigned ientries = 0;
215  for (map<string, string>::const_iterator it_att = xattrs_.begin(),
216  it_att_end = xattrs_.end();
217  it_att != it_att_end;
218  ++it_att) {
219  // Only serialize non-blacklist items
220  if (blacklist != NULL) {
221  bool skip = false;
222  for (unsigned i_bl = 0; i_bl < blacklist->size(); ++i_bl) {
223  if (HasPrefix(it_att->first, (*blacklist)[i_bl],
224  true /* ignore_case */)) {
225  skip = true;
226  break;
227  }
228  }
229  if (skip)
230  continue;
231  }
232  /*entries[ientries] =*/
233  new (entries + ientries) XattrEntry(it_att->first, it_att->second);
234  packed_size += entries[ientries].GetSize();
235  ientries++;
236  }
237 
238  // We might have skipped all attributes
239  if (ientries == 0) {
240  free(entries);
241  *size = 0;
242  *outbuf = NULL;
243  return;
244  }
245 
246  // Copy data into buffer
247  header.num_xattrs = ientries;
248  *size = packed_size;
249  *outbuf = reinterpret_cast<unsigned char *>(smalloc(packed_size));
250  memcpy(*outbuf, &header, sizeof(header));
251  unsigned pos = sizeof(header);
252  for (unsigned i = 0; i < header.num_xattrs; ++i) {
253  memcpy(*outbuf + pos, &entries[i], entries[i].GetSize());
254  pos += entries[i].GetSize();
255  }
256 
257  free(entries);
258 }
259 
260 
261 //------------------------------------------------------------------------------
262 
263 
265  if (len_key == 0)
266  return "";
267  return string(data, len_key);
268 }
269 
270 
272  return sizeof(len_key) + sizeof(len_value) + uint16_t(len_key)
273  + uint16_t(len_value);
274 }
275 
276 
278  if (len_value == 0)
279  return "";
280  return string(&data[len_key], len_value);
281 }
282 
283 
284 XattrList::XattrEntry::XattrEntry(const string &key, const string &value)
285  : len_key(key.size()), len_value(value.size()) {
286  memcpy(data, key.data(), len_key);
287  memcpy(data + len_key, value.data(), len_value);
288 }
std::string ListKeysPosix(const std::string &merge_with) const
Definition: xattr.cc:139
char data[512]
Definition: xattr.h:68
bool Set(const std::string &key, const std::string &value)
Definition: xattr.cc:163
assert((mem||(size==0))&&"Out Of Memory")
uint16_t GetSize() const
Definition: xattr.cc:271
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:109
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:306
std::string GetValue() const
Definition: xattr.cc:277
void Serialize(unsigned char **outbuf, unsigned *size, const std::vector< std::string > *blacklist=NULL) const
Definition: xattr.cc:199
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:104
std::string GetKey() const
Definition: xattr.cc:264
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:120
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:185