~clint-fewbar/+junk/ceph-packaging

« back to all changes in this revision

Viewing changes to src/rgw/rgw_fs.cc

  • Committer: Clint Byrum
  • Date: 2010-07-21 04:26:29 UTC
  • Revision ID: clint@ubuntu.com-20100721042629-srvi3wzjib97px3o
importingĀ upstreamĀ v0.20.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <errno.h>
 
2
#include <stdlib.h>
 
3
#include <dirent.h>
 
4
#include <limits.h>
 
5
#include <string.h>
 
6
#include <sys/types.h>
 
7
#include <sys/stat.h>
 
8
#include <unistd.h>
 
9
#include <sys/stat.h>
 
10
#include <fcntl.h>
 
11
#include <sys/xattr.h>
 
12
 
 
13
#include "rgw_access.h"
 
14
#include "rgw_fs.h"
 
15
 
 
16
#include <string>
 
17
#include <iostream>
 
18
#include <vector>
 
19
#include <map>
 
20
 
 
21
using namespace std;
 
22
 
 
23
struct rgwfs_state {
 
24
  DIR *dir;
 
25
};
 
26
 
 
27
#define DIR_NAME "/tmp/radosgw"
 
28
 
 
29
int RGWFS::list_buckets_init(string& id, RGWAccessHandle *handle)
 
30
{
 
31
  DIR *dir = opendir(DIR_NAME);
 
32
  struct rgwfs_state *state;
 
33
 
 
34
  if (!dir)
 
35
    return -errno;
 
36
 
 
37
  state = (struct rgwfs_state *)malloc(sizeof(struct rgwfs_state));
 
38
  if (!state)
 
39
    return -ENOMEM;
 
40
 
 
41
  state->dir = dir;
 
42
 
 
43
  *handle = (RGWAccessHandle)state;
 
44
 
 
45
  return 0;
 
46
}
 
47
 
 
48
int RGWFS::list_buckets_next(string& id, RGWObjEnt& obj, RGWAccessHandle *handle)
 
49
{
 
50
  struct rgwfs_state *state;
 
51
  struct dirent *dirent;
 
52
#define BUF_SIZE 512
 
53
 
 
54
  if (!handle)
 
55
    return -EINVAL;
 
56
  state = *(struct rgwfs_state **)handle;
 
57
 
 
58
  if (!state)
 
59
    return -EINVAL;
 
60
 
 
61
  while (1) {
 
62
    dirent = readdir(state->dir);
 
63
    if (!dirent) {
 
64
      closedir(state->dir);
 
65
      *handle = NULL;
 
66
      return -ENOENT;
 
67
    }
 
68
 
 
69
    if (dirent->d_name[0] == '.')
 
70
      continue;
 
71
 
 
72
    obj.name = dirent->d_name;
 
73
 
 
74
    char buf[BUF_SIZE];
 
75
    struct stat statbuf;
 
76
    snprintf(buf, BUF_SIZE, "%s/%s", DIR_NAME, obj.name.c_str());
 
77
    if (stat(buf, &statbuf) < 0)
 
78
      continue;
 
79
    obj.mtime = statbuf.st_mtime;
 
80
    obj.size = statbuf.st_size;
 
81
    return 0;
 
82
  }
 
83
}
 
84
 
 
85
int RGWFS::list_objects(string& id, string& bucket, int max, string& prefix, string& delim,
 
86
                       string& marker, vector<RGWObjEnt>& result, map<string, bool>& common_prefixes)
 
87
{
 
88
  map<string, bool> dir_map;
 
89
  char path[BUF_SIZE];
 
90
 
 
91
  snprintf(path, BUF_SIZE, "%s/%s", DIR_NAME, bucket.c_str());
 
92
 
 
93
  DIR *dir = opendir(path);
 
94
  if (!dir)
 
95
    return -errno;
 
96
 
 
97
  while (1) {
 
98
    struct dirent *dirent;
 
99
    dirent = readdir(dir);
 
100
    if (!dirent)
 
101
      break;
 
102
    if (dirent->d_name[0] == '.')
 
103
      continue;
 
104
 
 
105
    if (prefix.empty() ||
 
106
        (prefix.compare(0, prefix.size(), prefix) == 0)) {
 
107
      dir_map[dirent->d_name] = true;
 
108
    }
 
109
  }
 
110
 
 
111
  closedir(dir);
 
112
 
 
113
 
 
114
  map<string, bool>::iterator iter;
 
115
  if (!marker.empty())
 
116
    iter = dir_map.lower_bound(marker);
 
117
  else
 
118
    iter = dir_map.begin();
 
119
 
 
120
  if (max < 0)
 
121
    max = INT_MAX;
 
122
 
 
123
  result.clear();
 
124
  int i;
 
125
  for (i=0; i<max && iter != dir_map.end(); i++, ++iter) {
 
126
    RGWObjEnt obj;
 
127
    char buf[BUF_SIZE];
 
128
    struct stat statbuf;
 
129
    obj.name = iter->first;
 
130
    snprintf(buf, BUF_SIZE, "%s/%s", path, obj.name.c_str());
 
131
    if (stat(buf, &statbuf) < 0)
 
132
      continue;
 
133
    obj.mtime = statbuf.st_mtime;
 
134
    obj.size = statbuf.st_size;
 
135
    char *etag;
 
136
    if (get_attr(RGW_ATTR_ETAG, buf, &etag) >= 0) {
 
137
      strncpy(obj.etag, etag, sizeof(obj.etag));
 
138
      obj.etag[sizeof(obj.etag)-1] = '\0';
 
139
      free(etag);
 
140
    }
 
141
    result.push_back(obj);
 
142
  }
 
143
 
 
144
  return i;
 
145
}
 
146
 
 
147
 
 
148
int RGWFS::create_bucket(std::string& id, std::string& bucket, map<std::string, bufferlist>& attrs, uint64_t auid)
 
149
{
 
150
  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1;
 
151
  char buf[len];
 
152
  snprintf(buf, len, "%s/%s", DIR_NAME, bucket.c_str());
 
153
 
 
154
  if (mkdir(buf, 0755) < 0)
 
155
    return -errno;
 
156
 
 
157
  map<std::string, bufferlist>::iterator iter;
 
158
  for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
 
159
    const string& name = iter->first;
 
160
    bufferlist& bl = iter->second;
 
161
    
 
162
    if (bl.length()) {
 
163
      int r = setxattr(buf, name.c_str(), bl.c_str(), bl.length(), 0);
 
164
      if (r < 0) {
 
165
        r = -errno;
 
166
        rmdir(buf);
 
167
        return r;
 
168
      }
 
169
    }
 
170
  }
 
171
 
 
172
  return 0;
 
173
}
 
174
 
 
175
int RGWFS::put_obj(std::string& id, std::string& bucket, std::string& obj, const char *data, size_t size,
 
176
                  time_t *mtime,
 
177
                  map<string, bufferlist>& attrs)
 
178
{
 
179
  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
 
180
  char buf[len];
 
181
  snprintf(buf, len, "%s/%s/%s", DIR_NAME, bucket.c_str(), obj.c_str());
 
182
  int fd;
 
183
 
 
184
  fd = open(buf, O_CREAT | O_WRONLY, 0755);
 
185
  if (fd < 0)
 
186
    return -errno;
 
187
 
 
188
  int r;
 
189
  map<string, bufferlist>::iterator iter;
 
190
  for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
 
191
    const string& name = iter->first;
 
192
    bufferlist& bl = iter->second;
 
193
    
 
194
    if (bl.length()) {
 
195
      r = fsetxattr(fd, name.c_str(), bl.c_str(), bl.length(), 0);
 
196
      if (r < 0) {
 
197
        r = -errno;
 
198
        close(fd);
 
199
        return r;
 
200
      }
 
201
    }
 
202
  }
 
203
 
 
204
  r = write(fd, data, size);
 
205
  if (r < 0) {
 
206
    r = -errno;
 
207
    close(fd);
 
208
    unlink(buf);
 
209
    return r;
 
210
  }
 
211
 
 
212
  if (mtime) {
 
213
    struct stat st;
 
214
    r = fstat(fd, &st);
 
215
    if (r < 0) {
 
216
      r = -errno;
 
217
      close(fd);
 
218
      unlink(buf);
 
219
      return -errno;
 
220
    }
 
221
    *mtime = st.st_mtime;
 
222
  }
 
223
 
 
224
  r = close(fd);
 
225
  if (r < 0)
 
226
    return -errno;
 
227
 
 
228
  return 0;
 
229
}
 
230
 
 
231
int RGWFS::copy_obj(std::string& id, std::string& dest_bucket, std::string& dest_obj,
 
232
               std::string& src_bucket, std::string& src_obj,
 
233
               time_t *mtime,
 
234
               const time_t *mod_ptr,
 
235
               const time_t *unmod_ptr,
 
236
               const char *if_match,
 
237
               const char *if_nomatch,
 
238
               map<string, bufferlist>& attrs,
 
239
               struct rgw_err *err)
 
240
{
 
241
  int ret;
 
242
  char *data;
 
243
 
 
244
  map<string, bufferlist> attrset;
 
245
  ret = get_obj(src_bucket, src_obj, &data, 0, -1, &attrset,
 
246
                mod_ptr, unmod_ptr, if_match, if_nomatch, true, err);
 
247
  if (ret < 0)
 
248
    return ret;
 
249
 
 
250
  map<string, bufferlist>::iterator iter;
 
251
  for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
 
252
    attrset[iter->first] = iter->second;
 
253
  }
 
254
  attrs = attrset;
 
255
 
 
256
  ret = put_obj(id, dest_bucket, dest_obj, data, ret, mtime, attrs);
 
257
 
 
258
  return ret;
 
259
}
 
260
 
 
261
 
 
262
int RGWFS::delete_bucket(std::string& id, std::string& bucket)
 
263
{
 
264
  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1;
 
265
  char buf[len];
 
266
  snprintf(buf, len, "%s/%s", DIR_NAME, bucket.c_str());
 
267
 
 
268
  if (rmdir(buf) < 0)
 
269
    return -errno;
 
270
 
 
271
  return 0;
 
272
}
 
273
 
 
274
 
 
275
int RGWFS::delete_obj(std::string& id, std::string& bucket, std::string& obj)
 
276
{
 
277
  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
 
278
  char buf[len];
 
279
  snprintf(buf, len, "%s/%s/%s", DIR_NAME, bucket.c_str(), obj.c_str());
 
280
 
 
281
  if (unlink(buf) < 0)
 
282
    return -errno;
 
283
 
 
284
  return 0;
 
285
}
 
286
 
 
287
int RGWFS::get_attr(const char *name, int fd, char **attr)
 
288
{
 
289
  char *attr_buf;
 
290
#define ETAG_LEN 32
 
291
  size_t len = ETAG_LEN;
 
292
  ssize_t attr_len;
 
293
 
 
294
  while (1) {  
 
295
    attr_buf = (char *)malloc(len);
 
296
    attr_len = fgetxattr(fd, name, attr_buf, len);
 
297
    if (attr_len  > 0)
 
298
      break;
 
299
 
 
300
    free(attr_buf);
 
301
    switch (errno) {
 
302
    case ERANGE:
 
303
      break;
 
304
    default:
 
305
      return -errno;
 
306
    }
 
307
    len *= 2;
 
308
  }
 
309
  *attr = attr_buf;
 
310
 
 
311
  return attr_len;
 
312
}
 
313
 
 
314
int RGWFS::get_attr(const char *name, const char *path, char **attr)
 
315
{
 
316
  char *attr_buf;
 
317
  size_t len = ETAG_LEN;
 
318
  ssize_t attr_len;
 
319
 
 
320
  while (1) {  
 
321
    attr_buf = (char *)malloc(len);
 
322
    attr_len = getxattr(path, name, attr_buf, len);
 
323
    if (attr_len  > 0)
 
324
      break;
 
325
 
 
326
    free(attr_buf);
 
327
    switch (errno) {
 
328
    case ERANGE:
 
329
      break;
 
330
    default:
 
331
      cerr << "getxattr on " << path << " returned" << -errno << std::endl;
 
332
      return -errno;
 
333
    }
 
334
    len *= 2;
 
335
  }
 
336
  *attr = attr_buf;
 
337
 
 
338
  return attr_len;
 
339
}
 
340
 
 
341
int RGWFS::get_attr(std::string& bucket, std::string& obj,
 
342
                       const char *name, bufferlist& dest)
 
343
{
 
344
  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
 
345
  char buf[len];
 
346
  int r = -EINVAL;
 
347
  char *data = NULL;
 
348
 
 
349
  snprintf(buf, len, "%s/%s/%s", DIR_NAME, bucket.c_str(), obj.c_str());
 
350
 
 
351
  r = get_attr(name, buf, &data);
 
352
  if (r < 0)
 
353
      goto done;
 
354
  dest.append(data, r);
 
355
done:
 
356
  free(data);
 
357
 
 
358
  return r;
 
359
}
 
360
 
 
361
int RGWFS::set_attr(std::string& bucket, std::string& obj,
 
362
                       const char *name, bufferlist& bl)
 
363
{
 
364
  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
 
365
  char buf[len];
 
366
  int r;
 
367
 
 
368
  snprintf(buf, len, "%s/%s/%s", DIR_NAME, bucket.c_str(), obj.c_str());
 
369
 
 
370
  r = setxattr(buf, name, bl.c_str(), bl.length(), 0);
 
371
 
 
372
  int ret = (r < 0 ? -errno : 0);
 
373
  cerr << "setxattr: path=" << buf << " ret=" << ret << std::endl;
 
374
 
 
375
  return ret;
 
376
}
 
377
 
 
378
int RGWFS::get_obj(std::string& bucket, std::string& obj, 
 
379
            char **data, off_t ofs, off_t end,
 
380
            map<string, bufferlist> *attrs,
 
381
            const time_t *mod_ptr,
 
382
            const time_t *unmod_ptr,
 
383
            const char *if_match,
 
384
            const char *if_nomatch,
 
385
            bool get_data,
 
386
            struct rgw_err *err)
 
387
{
 
388
  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
 
389
  char buf[len];
 
390
  int fd;
 
391
  struct stat st;
 
392
  int r = -EINVAL;
 
393
  size_t max_len, pos;
 
394
  char *etag = NULL;
 
395
 
 
396
  snprintf(buf, len, "%s/%s/%s", DIR_NAME, bucket.c_str(), obj.c_str());
 
397
 
 
398
  fd = open(buf, O_RDONLY, 0755);
 
399
 
 
400
  if (fd < 0)
 
401
    return -errno;
 
402
 
 
403
  r = fstat(fd, &st);
 
404
  if (r < 0)
 
405
    return -errno;
 
406
 
 
407
  if (end < 0)
 
408
    end = st.st_size - 1;
 
409
 
 
410
  max_len = end - ofs + 1;
 
411
 
 
412
  r = -ECANCELED;
 
413
  if (mod_ptr) {
 
414
    if (st.st_mtime < *mod_ptr) {
 
415
      err->num = "304";
 
416
      err->code = "PreconditionFailed";
 
417
      goto done;
 
418
    }
 
419
  }
 
420
 
 
421
  if (unmod_ptr) {
 
422
    if (st.st_mtime >= *mod_ptr) {
 
423
      err->num = "412";
 
424
      err->code = "PreconditionFailed";
 
425
      goto done;
 
426
    }
 
427
  }
 
428
  if (if_match || if_nomatch) {
 
429
    r = get_attr(RGW_ATTR_ETAG, fd, &etag);
 
430
    if (r < 0)
 
431
      goto done;
 
432
 
 
433
    r = -ECANCELED;
 
434
    if (if_match) {
 
435
      cerr << "etag=" << etag << " " << " if_match=" << if_match << endl;
 
436
      if (strcmp(if_match, etag)) {
 
437
        err->num = "412";
 
438
        err->code = "PreconditionFailed";
 
439
        goto done;
 
440
      }
 
441
    }
 
442
 
 
443
    if (if_nomatch) {
 
444
      cerr << "etag=" << etag << " " << " if_nomatch=" << if_nomatch << endl;
 
445
      if (strcmp(if_nomatch, etag) == 0) {
 
446
        err->num = "412";
 
447
        err->code = "PreconditionFailed";
 
448
        goto done;
 
449
      }
 
450
    }
 
451
  }
 
452
 
 
453
  if (!get_data) {
 
454
    r = max_len;
 
455
    goto done;
 
456
  }
 
457
  *data = (char *)malloc(max_len);
 
458
  if (!*data) {
 
459
    r = -ENOMEM;
 
460
    goto done;
 
461
  }
 
462
 
 
463
  pos = 0;
 
464
  while (pos < max_len) {
 
465
    r = read(fd, (*data) + pos, max_len);
 
466
    if (r > 0) {
 
467
      pos += r;
 
468
    } else {
 
469
      if (!r) {
 
470
        cerr << "pos=" << pos << " r=" << r << " max_len=" << max_len << endl;
 
471
        r = -EIO; /* should not happen as we validated file size earlier */
 
472
        goto done;
 
473
      }
 
474
      switch (errno) {
 
475
      case EINTR:
 
476
        break;
 
477
      default:
 
478
        r = -errno;
 
479
        goto done;
 
480
      }
 
481
    }
 
482
  } 
 
483
 
 
484
  r = max_len;
 
485
done:
 
486
  free(etag);
 
487
  close(fd);  
 
488
 
 
489
  return r;
 
490
}
 
491
 
 
492