glusterfs
698 строк · 15.5 Кб
1/*
2Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
3This file is part of GlusterFS.
4
5This file is licensed to you under your choice of the GNU Lesser
6General Public License, version 3 or any later version (LGPLv3 or
7later), or the GNU General Public License, version 2 (GPLv2), in all
8cases as published by the Free Software Foundation.
9*/
10
11#include <inttypes.h>12#include <libgen.h>13
14#include <glusterfs/logging.h>15#include "glusterfs/store.h"16#include "glusterfs/xlator.h"17#include "glusterfs/syscall.h"18#include "glusterfs/libglusterfs-messages.h"19
20int32_t
21gf_store_mkdir(char *path)22{
23int32_t ret = -1;24
25ret = mkdir_p(path, 0755, _gf_true);26
27if ((-1 == ret) && (EEXIST != errno)) {28gf_msg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED,29"mkdir()"30" failed on path %s.",31path);32} else {33ret = 0;34}35
36return ret;37}
38
39int32_t
40gf_store_handle_create_on_absence(gf_store_handle_t **shandle, char *path)41{
42GF_ASSERT(shandle);43int32_t ret = 0;44
45if (*shandle == NULL) {46ret = gf_store_handle_new(path, shandle);47
48if (ret) {49gf_msg("", GF_LOG_ERROR, 0, LG_MSG_STORE_HANDLE_CREATE_FAILED,50"Unable to"51" create store handle for path: %s",52path);53}54}55return ret;56}
57
58int32_t
59gf_store_mkstemp(gf_store_handle_t *shandle)60{
61char tmppath[PATH_MAX] = {620,63};64
65GF_VALIDATE_OR_GOTO("store", shandle, out);66GF_VALIDATE_OR_GOTO("store", shandle->path, out);67
68snprintf(tmppath, sizeof(tmppath), "%s.tmp", shandle->path);69shandle->tmp_fd = open(tmppath, O_RDWR | O_CREAT | O_TRUNC, 0600);70if (shandle->tmp_fd < 0) {71gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,72"Failed to open %s.", tmppath);73}74out:75return shandle->tmp_fd;76}
77
78int
79gf_store_sync_direntry(char *path)80{
81int ret = -1;82int dirfd = -1;83char *dir = NULL;84char *pdir = NULL;85xlator_t *this = NULL;86
87this = THIS;88
89dir = gf_strdup(path);90if (!dir)91goto out;92
93pdir = dirname(dir);94dirfd = open(pdir, O_RDONLY);95if (dirfd == -1) {96gf_msg(this->name, GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED,97"Failed to open directory %s.", pdir);98goto out;99}100
101ret = sys_fsync(dirfd);102if (ret) {103gf_msg(this->name, GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED,104"Failed to fsync %s.", pdir);105goto out;106}107
108ret = 0;109out:110if (dirfd >= 0) {111ret = sys_close(dirfd);112if (ret) {113gf_msg(this->name, GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED,114"Failed to close %s", pdir);115}116}117
118if (dir)119GF_FREE(dir);120
121return ret;122}
123
124int32_t
125gf_store_rename_tmppath(gf_store_handle_t *shandle)126{
127int32_t ret = -1;128char tmppath[PATH_MAX] = {1290,130};131
132GF_VALIDATE_OR_GOTO("store", shandle, out);133GF_VALIDATE_OR_GOTO("store", shandle->path, out);134
135ret = sys_fsync(shandle->tmp_fd);136if (ret) {137gf_msg(THIS->name, GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,138"Failed to fsync %s", shandle->path);139goto out;140}141snprintf(tmppath, sizeof(tmppath), "%s.tmp", shandle->path);142ret = sys_rename(tmppath, shandle->path);143if (ret) {144gf_msg(THIS->name, GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,145"Failed to rename %s to %s", tmppath, shandle->path);146goto out;147}148
149ret = gf_store_sync_direntry(tmppath);150out:151if (shandle && shandle->tmp_fd >= 0) {152sys_close(shandle->tmp_fd);153shandle->tmp_fd = -1;154}155return ret;156}
157
158int32_t
159gf_store_unlink_tmppath(gf_store_handle_t *shandle)160{
161int32_t ret = -1;162char tmppath[PATH_MAX] = {1630,164};165
166GF_VALIDATE_OR_GOTO("store", shandle, out);167GF_VALIDATE_OR_GOTO("store", shandle->path, out);168
169snprintf(tmppath, sizeof(tmppath), "%s.tmp", shandle->path);170ret = gf_unlink(tmppath) ? 0 : -1;171out:172if (shandle && shandle->tmp_fd >= 0) {173sys_close(shandle->tmp_fd);174shandle->tmp_fd = -1;175}176return ret;177}
178
179int
180gf_store_read_and_tokenize(FILE *file, char **iter_key, char **iter_val,181gf_store_op_errno_t *store_errno, char *str,182size_t buf_size)183{
184int32_t ret = -1;185char *savetok = NULL;186char *key = NULL;187char *value = NULL;188char *temp = NULL;189size_t str_len = 0;190
191GF_ASSERT(file);192GF_ASSERT(iter_key);193GF_ASSERT(iter_val);194GF_ASSERT(store_errno);195
196str[0] = '\0';197
198retry:199temp = fgets(str, buf_size, file);200if (temp == NULL || feof(file)) {201ret = -1;202*store_errno = GD_STORE_EOF;203goto out;204}205
206if (strcmp(str, "\n") == 0)207goto retry;208
209str_len = strlen(str);210str[str_len - 1] = '\0';211/* Truncate the "\n", as fgets stores "\n" in str */212
213key = strtok_r(str, "=", &savetok);214if (!key) {215ret = -1;216*store_errno = GD_STORE_KEY_NULL;217goto out;218}219
220value = strtok_r(NULL, "", &savetok);221if (!value) {222ret = -1;223*store_errno = GD_STORE_VALUE_NULL;224goto out;225}226
227*iter_key = key;228*iter_val = value;229*store_errno = GD_STORE_SUCCESS;230ret = 0;231out:232return ret;233}
234
235int32_t
236gf_store_retrieve_value(gf_store_handle_t *handle, char *key, char **value)237{
238int32_t ret = -1;239char *iter_key = NULL;240char *iter_val = NULL;241gf_store_op_errno_t store_errno = GD_STORE_SUCCESS;242
243GF_ASSERT(handle);244
245if (handle->locked == F_ULOCK)246/* no locking is used handle->fd gets closed() after usage */247handle->fd = open(handle->path, O_RDWR);248else249/* handle->fd is valid already, kept open for lockf() */250sys_lseek(handle->fd, 0, SEEK_SET);251
252if (handle->fd == -1) {253gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,254"Unable to open file %s", handle->path);255goto out;256}257if (!handle->read) {258int duped_fd = dup(handle->fd);259
260if (duped_fd >= 0)261handle->read = fdopen(duped_fd, "r");262if (!handle->read) {263if (duped_fd != -1)264sys_close(duped_fd);265gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,266"Unable to open file %s", handle->path);267goto out;268}269} else {270fseek(handle->read, 0, SEEK_SET);271}272
273char buf[8192];274do {275ret = gf_store_read_and_tokenize(handle->read, &iter_key, &iter_val,276&store_errno, buf, 8192);277if (ret < 0) {278gf_msg_trace("", 0,279"error while reading key '%s': "280"%s",281key, gf_store_strerror(store_errno));282goto out;283}284
285gf_msg_trace("", 0, "key %s read", iter_key);286
287if (!strcmp(key, iter_key)) {288gf_msg_debug("", 0, "key %s found", key);289ret = 0;290if (iter_val)291*value = gf_strdup(iter_val);292goto out;293}294} while (1);295out:296if (handle->read) {297fclose(handle->read);298handle->read = NULL;299}300
301if (handle->fd > 0 && handle->locked == F_ULOCK) {302/* only invalidate handle->fd if not locked */303sys_close(handle->fd);304}305
306return ret;307}
308
309int32_t
310gf_store_save_value(int fd, char *key, char *value)311{
312int32_t ret = -1;313int dup_fd = -1;314FILE *fp = NULL;315
316GF_ASSERT(fd > 0);317GF_ASSERT(key);318GF_ASSERT(value);319
320dup_fd = dup(fd);321if (dup_fd == -1)322goto out;323
324fp = fdopen(dup_fd, "a+");325if (fp == NULL) {326gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,327"fdopen failed.");328ret = -1;329goto out;330}331
332ret = fprintf(fp, "%s=%s\n", key, value);333if (ret < 0) {334gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,335"Unable to store key: %s, value: %s.", key, value);336ret = -1;337goto out;338}339
340ret = fflush(fp);341if (ret) {342gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,343"fflush failed.");344ret = -1;345goto out;346}347
348ret = 0;349out:350if (fp)351fclose(fp);352
353gf_msg_debug(THIS->name, 0, "returning: %d", ret);354return ret;355}
356
357int32_t
358gf_store_save_items(int fd, char *items)359{
360int32_t ret = -1;361int dup_fd = -1;362FILE *fp = NULL;363
364GF_ASSERT(fd > 0);365GF_ASSERT(items);366
367dup_fd = dup(fd);368if (dup_fd == -1)369goto out;370
371fp = fdopen(dup_fd, "a+");372if (fp == NULL) {373gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,374"fdopen failed.");375ret = -1;376goto out;377}378
379ret = fputs(items, fp);380if (ret < 0) {381gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,382"Unable to store items: %s", items);383ret = -1;384goto out;385}386
387ret = fflush(fp);388if (ret) {389gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,390"fflush failed.");391ret = -1;392goto out;393}394
395ret = 0;396out:397if (fp)398fclose(fp);399
400gf_msg_debug(THIS->name, 0, "returning: %d", ret);401return ret;402}
403
404int32_t
405gf_store_handle_new(const char *path, gf_store_handle_t **handle)406{
407int32_t ret = -1;408gf_store_handle_t *shandle = NULL;409int fd = -1;410char *spath = NULL;411
412shandle = GF_CALLOC(1, sizeof(*shandle), gf_common_mt_store_handle_t);413if (!shandle)414goto out;415
416spath = gf_strdup(path);417if (!spath)418goto out;419
420fd = open(path, O_RDWR | O_CREAT | O_APPEND, 0600);421if (fd < 0) {422gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,423"Failed to open file: %s.", path);424goto out;425}426
427ret = gf_store_sync_direntry(spath);428if (ret)429goto out;430
431shandle->path = spath;432shandle->locked = F_ULOCK;433*handle = shandle;434shandle->tmp_fd = -1;435
436ret = 0;437out:438if (fd >= 0)439sys_close(fd);440
441if (ret) {442GF_FREE(spath);443GF_FREE(shandle);444}445
446gf_msg_debug("", 0, "Returning %d", ret);447return ret;448}
449
450int
451gf_store_handle_retrieve(char *path, gf_store_handle_t **handle)452{
453int32_t ret = -1;454struct stat statbuf = {0};455
456ret = sys_stat(path, &statbuf);457if (ret) {458gf_msg("", GF_LOG_ERROR, errno, LG_MSG_PATH_NOT_FOUND,459"Path "460"corresponding to %s.",461path);462goto out;463}464ret = gf_store_handle_new(path, handle);465out:466gf_msg_debug("", 0, "Returning %d", ret);467return ret;468}
469
470int32_t
471gf_store_handle_destroy(gf_store_handle_t *handle)472{
473int32_t ret = -1;474
475if (!handle) {476ret = 0;477goto out;478}479
480GF_FREE(handle->path);481
482GF_FREE(handle);483
484ret = 0;485
486out:487gf_msg_debug("", 0, "Returning %d", ret);488
489return ret;490}
491
492int32_t
493gf_store_iter_new(gf_store_handle_t *shandle, gf_store_iter_t **iter)494{
495int32_t ret = -1;496FILE *fp = NULL;497gf_store_iter_t *tmp_iter = NULL;498
499GF_ASSERT(shandle);500GF_ASSERT(iter);501
502fp = fopen(shandle->path, "r");503if (!fp) {504gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,505"Unable to open file %s", shandle->path);506goto out;507}508
509tmp_iter = GF_MALLOC(sizeof(*tmp_iter), gf_common_mt_store_iter_t);510if (!tmp_iter)511goto out;512
513tmp_iter->file = fp;514if (snprintf(tmp_iter->filepath, sizeof(tmp_iter->filepath), "%s",515shandle->path) >= sizeof(tmp_iter->filepath))516goto out;517tmp_iter->buf[0] = '\0';518
519*iter = tmp_iter;520tmp_iter = NULL;521ret = 0;522
523out:524if (ret && fp)525fclose(fp);526
527GF_FREE(tmp_iter);528
529gf_msg_debug("", 0, "Returning with %d", ret);530return ret;531}
532
533int32_t
534gf_store_iter_get_next(gf_store_iter_t *iter, char **key, char **value,535gf_store_op_errno_t *op_errno)536{
537int32_t ret = -1;538char *iter_key = NULL;539char *iter_val = NULL;540
541gf_store_op_errno_t store_errno = GD_STORE_SUCCESS;542
543GF_ASSERT(iter);544GF_ASSERT(key);545GF_ASSERT(value);546
547ret = gf_store_read_and_tokenize(iter->file, &iter_key, &iter_val,548&store_errno, iter->buf, sizeof(iter->buf));549if (ret < 0) {550goto out;551}552
553*key = gf_strdup(iter_key);554if (!*key) {555ret = -1;556store_errno = GD_STORE_ENOMEM;557goto out;558}559*value = gf_strdup(iter_val);560if (!*value) {561ret = -1;562store_errno = GD_STORE_ENOMEM;563goto out;564}565ret = 0;566
567out:568if (ret) {569GF_FREE(*key);570GF_FREE(*value);571*key = NULL;572*value = NULL;573}574if (op_errno)575*op_errno = store_errno;576
577gf_msg_debug("", 0, "Returning with %d", ret);578return ret;579}
580
581int32_t
582gf_store_iter_get_matching(gf_store_iter_t *iter, char *key, char **value)583{
584int32_t ret = -1;585char *tmp_key = NULL;586char *tmp_value = NULL;587
588ret = gf_store_iter_get_next(iter, &tmp_key, &tmp_value, NULL);589while (!ret) {590if (!strncmp(key, tmp_key, strlen(key))) {591*value = tmp_value;592GF_FREE(tmp_key);593goto out;594}595GF_FREE(tmp_key);596tmp_key = NULL;597GF_FREE(tmp_value);598tmp_value = NULL;599ret = gf_store_iter_get_next(iter, &tmp_key, &tmp_value, NULL);600}601out:602return ret;603}
604
605int32_t
606gf_store_iter_destroy(gf_store_iter_t **iter)607{
608int32_t ret = -1;609
610if (!(*iter))611return 0;612
613/* gf_store_iter_new will not return a valid iter object with iter->file614* being NULL*/
615ret = fclose((*iter)->file);616if (ret)617gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,618"Unable"619" to close file: %s, ret: %d",620(*iter)->filepath, ret);621
622GF_FREE(*iter);623*iter = NULL;624
625return ret;626}
627
628char *629gf_store_strerror(gf_store_op_errno_t op_errno)630{
631switch (op_errno) {632case GD_STORE_SUCCESS:633return "Success";634case GD_STORE_KEY_NULL:635return "Invalid Key";636case GD_STORE_VALUE_NULL:637return "Invalid Value";638case GD_STORE_KEY_VALUE_NULL:639return "Invalid Key and Value";640case GD_STORE_EOF:641return "No data";642case GD_STORE_ENOMEM:643return "No memory";644default:645return "Invalid errno";646}647}
648
649int
650gf_store_lock(gf_store_handle_t *sh)651{
652int ret;653
654GF_ASSERT(sh);655GF_ASSERT(sh->path);656GF_ASSERT(sh->locked == F_ULOCK);657
658sh->fd = open(sh->path, O_RDWR);659if (sh->fd == -1) {660gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,661"Failed to open '%s'", sh->path);662return -1;663}664
665ret = lockf(sh->fd, F_LOCK, 0);666if (ret)667gf_msg("", GF_LOG_ERROR, errno, LG_MSG_LOCK_FAILED,668"Failed to gain lock on '%s'", sh->path);669else670/* sh->locked is protected by the lockf(sh->fd) above */671sh->locked = F_LOCK;672
673return ret;674}
675
676void
677gf_store_unlock(gf_store_handle_t *sh)678{
679GF_ASSERT(sh);680GF_ASSERT(sh->locked == F_LOCK);681
682sh->locked = F_ULOCK;683
684/* does not matter if this fails, locks are released on close anyway */685if (lockf(sh->fd, F_ULOCK, 0) == -1)686gf_msg("", GF_LOG_ERROR, errno, LG_MSG_UNLOCK_FAILED,687"Failed to release lock on '%s'", sh->path);688
689sys_close(sh->fd);690}
691
692int
693gf_store_locked_local(gf_store_handle_t *sh)694{
695GF_ASSERT(sh);696
697return (sh->locked == F_LOCK);698}
699