CernVM-FS  2.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
xattr.cc
Go to the documentation of this file.
1 
5 #include "cvmfs_config.h"
6 #include "xattr.h"
7 
8 #include <alloca.h>
9 #include <sys/xattr.h>
10 
11 #include <cassert>
12 #include <cstring>
13 
14 #include "platform.h"
15 #include "smalloc.h"
16 #include "util/pointer.h"
17 #include "util/string.h"
18 
19 using namespace std; // NOLINT
20 
21 const uint8_t XattrList::kVersion = 1;
22 
30 XattrList *XattrList::CreateFromFile(const std::string &path) {
31  // Parse the \0 separated list of extended attribute keys
32  char *list;
33  ssize_t sz_list = platform_llistxattr(path.c_str(), NULL, 0);
34  if ((sz_list < 0) || (sz_list > 64*1024)) {
35  return NULL;
36  } else if (sz_list == 0) {
37  // No extended attributes
38  return new XattrList();
39  }
40  list = reinterpret_cast<char *>(alloca(sz_list));
41  sz_list = platform_llistxattr(path.c_str(), list, sz_list);
42  if (sz_list < 0) {
43  return NULL;
44  } else if (sz_list == 0) {
45  // Can only happen if the list was removed since the previous call to
46  // llistxattr
47  return new XattrList();
48  }
49  vector<string> keys = SplitString(string(list, sz_list), '\0');
50 
51  // Retrieve extended attribute values
52  XattrList *result = new XattrList();
53  char value[256];
54  for (unsigned i = 0; i < keys.size(); ++i) {
55  if (keys[i].empty())
56  continue;
57  ssize_t sz_value =
58  platform_lgetxattr(path.c_str(), keys[i].c_str(), value, 256);
59  if (sz_value < 0)
60  continue;
61  result->Set(keys[i], string(value, sz_value));
62  }
63  return result;
64 }
65 
66 
68  const unsigned char *inbuf,
69  const unsigned size)
70 {
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(); i != iEnd; ++i)
123  {
124  result.push_back(i->first);
125  }
126  return result;
127 }
128 
129 
137 string XattrList::ListKeysPosix(const string &merge_with) const {
138  string result;
139  if (!merge_with.empty()) {
140  vector<string> merge_list = SplitString(merge_with, '\0');
141  for (unsigned i = 0; i < merge_list.size(); ++i) {
142  if (merge_list[i].empty())
143  continue;
144  if (xattrs_.find(merge_list[i]) == xattrs_.end()) {
145  result += merge_list[i];
146  result.push_back('\0');
147  }
148  }
149  }
150  for (map<string, string>::const_iterator i = xattrs_.begin(),
151  iEnd = xattrs_.end(); i != iEnd; ++i)
152  {
153  result += i->first;
154  result.push_back('\0');
155  }
156  return result;
157 }
158 
159 
160 bool XattrList::Set(const string &key, const string &value) {
161  if (key.empty())
162  return false;
163  if (key.length() > 256)
164  return false;
165  if (key.find('\0') != string::npos)
166  return false;
167  if (value.length() > 256)
168  return false;
169 
170  map<string, string>::iterator iter = xattrs_.find(key);
171  if (iter != xattrs_.end()) {
172  iter->second = value;
173  } else {
174  if (xattrs_.size() >= 256)
175  return false;
176  xattrs_[key] = value;
177  }
178  return true;
179 }
180 
181 
182 bool XattrList::Remove(const string &key) {
183  map<string, string>::iterator iter = xattrs_.find(key);
184  if (iter != xattrs_.end()) {
185  xattrs_.erase(iter);
186  return true;
187  }
188  return false;
189 }
190 
191 
197  unsigned char **outbuf,
198  unsigned *size,
199  const std::vector<std::string> *blacklist) const
200 {
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(); it_att != it_att_end; ++it_att)
216  {
217  // Only serialize non-blacklist items
218  if (blacklist != NULL) {
219  bool skip = false;
220  for (unsigned i_bl = 0; i_bl < blacklist->size(); ++i_bl) {
221  if (HasPrefix(it_att->first, (*blacklist)[i_bl],
222  true /* ignore_case */))
223  {
224  skip = true;
225  break;
226  }
227  }
228  if (skip) continue;
229  }
230  /*entries[ientries] =*/
231  new (entries + ientries) XattrEntry(it_att->first, it_att->second);
232  packed_size += entries[ientries].GetSize();
233  ientries++;
234  }
235 
236  // We might have skipped all attributes
237  if (ientries == 0) {
238  free(entries);
239  *size = 0;
240  *outbuf = NULL;
241  return;
242  }
243 
244  // Copy data into buffer
245  header.num_xattrs = ientries;
246  *size = packed_size;
247  *outbuf = reinterpret_cast<unsigned char *>(smalloc(packed_size));
248  memcpy(*outbuf, &header, sizeof(header));
249  unsigned pos = sizeof(header);
250  for (unsigned i = 0; i < header.num_xattrs; ++i) {
251  memcpy(*outbuf + pos, &entries[i], entries[i].GetSize());
252  pos += entries[i].GetSize();
253  }
254 
255  free(entries);
256 }
257 
258 
259 //------------------------------------------------------------------------------
260 
261 
263  if (len_key == 0)
264  return "";
265  return string(data, len_key);
266 }
267 
268 
270  return sizeof(len_key) + sizeof(len_value) +
271  uint16_t(len_key) + uint16_t(len_value);
272 }
273 
274 
276  if (len_value == 0)
277  return "";
278  return string(&data[len_key], len_value);
279 }
280 
281 
282 XattrList::XattrEntry::XattrEntry(const string &key, const string &value)
283  : len_key(key.size())
284  , len_value(value.size())
285 {
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:137
char data[512]
Definition: xattr.h:70
vector< string > SplitString(const string &str, const char delim, const unsigned max_chunks)
Definition: string.cc:287
bool Set(const std::string &key, const std::string &value)
Definition: xattr.cc:160
assert((mem||(size==0))&&"Out Of Memory")
uint16_t GetSize() const
Definition: xattr.cc:269
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
std::string GetValue() const
Definition: xattr.cc:275
void Serialize(unsigned char **outbuf, unsigned *size, const std::vector< std::string > *blacklist=NULL) const
Definition: xattr.cc:196
ssize_t platform_lgetxattr(const char *path, const char *name, void *value, size_t size)
Definition: xattr.h:60
bool Has(const std::string &key) const
Definition: xattr.cc:103
std::string GetKey() const
Definition: xattr.cc:262
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:264
static XattrList * Deserialize(const unsigned char *inbuf, const unsigned size)
Definition: xattr.cc:67
uint8_t len_key
Definition: xattr.h:66
static XattrList * CreateFromFile(const std::string &path)
Definition: xattr.cc:30
static const uint8_t kVersion
Definition: xattr.h:29
uint8_t num_xattrs
Definition: xattr.h:58
const char * kVersion
Definition: preload.cc:27
std::vector< std::string > ListKeys() const
Definition: xattr.cc:119
XattrEntry()
Definition: xattr.h:62
uint8_t len_value
Definition: xattr.h:67
static void size_t size
Definition: smalloc.h:47
bool Remove(const std::string &key)
Definition: xattr.cc:182