glusterfs
618 строк · 15.0 Кб
1/*
2Copyright (c) 2008-2012 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 <stdlib.h>12#include <unistd.h>13#include <stdarg.h>14#include <getopt.h>15#include <sys/types.h>16#include <dirent.h>17
18#include "glusterfs/logging.h"19#include "glusterfs/compat.h"20#include "glusterfs/iatt.h"21#include "glusterfs/syscall.h"22#include "glusterfs/run.h"23#include "glusterfs/libglusterfs-messages.h"24
25#ifdef GF_SOLARIS_HOST_OS26int
27solaris_fsetxattr(int fd, const char *key, const char *value, size_t size,28int flags)29{
30int attrfd = -1;31int ret = 0;32
33attrfd = openat(fd, key, flags | O_CREAT | O_WRONLY | O_XATTR, 0777);34if (attrfd >= 0) {35ftruncate(attrfd, 0);36ret = write(attrfd, value, size);37close(attrfd);38} else {39if (errno != ENOENT)40gf_msg("libglusterfs", GF_LOG_ERROR, errno,41LG_MSG_SET_ATTRIBUTE_FAILED,42"Couldn't set "43"extended attribute for %d",44fd);45return -1;46}47
48return 0;49}
50
51int
52solaris_fgetxattr(int fd, const char *key, char *value, size_t size)53{
54int attrfd = -1;55int ret = 0;56
57attrfd = openat(fd, key, O_RDONLY | O_XATTR);58if (attrfd >= 0) {59if (size == 0) {60struct stat buf;61fstat(attrfd, &buf);62ret = buf.st_size;63} else {64ret = read(attrfd, value, size);65}66close(attrfd);67} else {68if (errno != ENOENT)69gf_msg("libglusterfs", GF_LOG_INFO, errno,70LG_MSG_READ_ATTRIBUTE_FAILED,71"Couldn't read "72"extended attribute for the file %d",73fd);74if (errno == ENOENT)75errno = ENODATA;76return -1;77}78
79return ret;80}
81
82/* Solaris does not support xattr for symlinks and dev files. Since gfid and
83other trusted attributes are stored as xattrs, we need to provide support for
84them. A mapped regular file is stored in the /.glusterfs_xattr_inode of the
85export dir. All xattr ops related to the special files are redirected to this
86map file.
87*/
88
89int
90make_export_path(const char *real_path, char **path)91{
92int ret = -1;93char *tmp = NULL;94char *export_path = NULL;95char *dup = NULL;96char *ptr = NULL;97char *freeptr = NULL;98uuid_t gfid = {990,100};101
102export_path = GF_CALLOC(1, sizeof(char) * PATH_MAX, 0);103if (!export_path)104goto out;105
106dup = gf_strdup(real_path);107if (!dup)108goto out;109
110freeptr = dup;111ret = solaris_getxattr("/", GFID_XATTR_KEY, gfid, 16);112/* Return value of getxattr */113if (ret == 16) {114if (__is_root_gfid(gfid)) {115strcat(export_path, "/");116ret = 0;117goto done;118}119}120
121do {122ptr = strtok_r(dup, "/", &tmp);123if (!ptr)124break;125strcat(export_path, dup);126ret = solaris_getxattr(export_path, GFID_XATTR_KEY, gfid, 16);127if (ret == 16) {128if (__is_root_gfid(gfid)) {129ret = 0;130goto done;131}132}133strcat(export_path, "/");134dup = tmp;135} while (ptr);136
137goto out;138
139done:140if (!ret) {141*path = export_path;142}143out:144GF_FREE(freeptr);145if (ret && export_path)146GF_FREE(export_path);147
148return ret;149}
150int
151solaris_xattr_resolve_path(const char *real_path, char **path)152{
153int ret = -1;154char *export_path = NULL;155char xattr_path[PATH_MAX] = {1560,157};158struct stat lstatbuf = {1590,160};161struct iatt stbuf = {1620,163};164struct stat statbuf = {1650,166};167
168ret = lstat(real_path, &lstatbuf);169if (ret != 0)170return ret;171iatt_from_stat(&stbuf, &lstatbuf);172if (IA_ISREG(stbuf.ia_type) || IA_ISDIR(stbuf.ia_type))173return -1;174
175ret = make_export_path(real_path, &export_path);176if (!ret && export_path) {177strcat(export_path, "/" GF_SOLARIS_XATTR_DIR);178if (lstat(export_path, &statbuf)) {179ret = mkdir(export_path, 0755);180if (ret && (errno != EEXIST)) {181gf_msg_debug(THIS->name, 0,182"mkdir failed,"183" errno: %d",184errno);185goto out;186}187}188
189snprintf(xattr_path, PATH_MAX, "%s%s%lu", export_path, "/",190stbuf.ia_ino);191
192ret = lstat(xattr_path, &statbuf);193
194if (ret) {195ret = mknod(xattr_path, S_IFREG | O_WRONLY, 0);196if (ret && (errno != EEXIST)) {197gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,198"Failed to "199"create mapped file %s",200xattr_path);201goto out;202}203}204*path = gf_strdup(xattr_path);205}206out:207GF_FREE(export_path);208if (*path)209return 0;210else211return -1;212}
213
214int
215solaris_setxattr(const char *path, const char *key, const char *value,216size_t size, int flags)217{
218int attrfd = -1;219int ret = 0;220char *mapped_path = NULL;221
222ret = solaris_xattr_resolve_path(path, &mapped_path);223if (!ret) {224attrfd = attropen(mapped_path, key, flags | O_CREAT | O_WRONLY, 0777);225} else {226attrfd = attropen(path, key, flags | O_CREAT | O_WRONLY, 0777);227}228if (attrfd >= 0) {229ftruncate(attrfd, 0);230ret = write(attrfd, value, size);231close(attrfd);232ret = 0;233} else {234if (errno != ENOENT)235gf_msg("libglusterfs", GF_LOG_ERROR, errno,236LG_MSG_SET_ATTRIBUTE_FAILED,237"Couldn't set "238"extended attribute for %s",239path);240ret = -1;241}242GF_FREE(mapped_path);243return ret;244}
245
246int
247solaris_listxattr(const char *path, char *list, size_t size)248{
249int attrdirfd = -1;250ssize_t len = 0;251DIR *dirptr = NULL;252struct dirent *dent = NULL;253int newfd = -1;254char *mapped_path = NULL;255int ret = -1;256
257ret = solaris_xattr_resolve_path(path, &mapped_path);258if (!ret) {259attrdirfd = attropen(mapped_path, ".", O_RDONLY, 0);260} else {261attrdirfd = attropen(path, ".", O_RDONLY, 0);262}263if (attrdirfd >= 0) {264newfd = dup(attrdirfd);265dirptr = fdopendir(newfd);266if (dirptr) {267while ((dent = readdir(dirptr))) {268size_t listlen = strlen(dent->d_name);269if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {270/* we don't want "." and ".." here */271continue;272}273if (size == 0) {274/* return the current size of the list275of extended attribute names*/
276len += listlen + 1;277} else {278/* check size and copy entry + null279into list. */
280if ((len + listlen + 1) > size) {281errno = ERANGE;282len = -1;283break;284} else {285strncpy(list + len, dent->d_name, listlen);286len += listlen;287list[len] = '\0';288++len;289}290}291}292
293if (closedir(dirptr) == -1) {294close(attrdirfd);295len = -1;296goto out;297}298} else {299close(attrdirfd);300len = -1;301goto out;302}303close(attrdirfd);304}305out:306GF_FREE(mapped_path);307return len;308}
309
310int
311solaris_flistxattr(int fd, char *list, size_t size)312{
313int attrdirfd = -1;314ssize_t len = 0;315DIR *dirptr = NULL;316struct dirent *dent = NULL;317int newfd = -1;318
319attrdirfd = openat(fd, ".", O_RDONLY, 0);320if (attrdirfd >= 0) {321newfd = dup(attrdirfd);322dirptr = fdopendir(newfd);323if (dirptr) {324while ((dent = readdir(dirptr))) {325size_t listlen = strlen(dent->d_name);326if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {327/* we don't want "." and ".." here */328continue;329}330if (size == 0) {331/* return the current size of the list332of extended attribute names*/
333len += listlen + 1;334} else {335/* check size and copy entry + null336into list. */
337if ((len + listlen + 1) > size) {338errno = ERANGE;339len = -1;340break;341} else {342strncpy(list + len, dent->d_name, listlen);343len += listlen;344list[len] = '\0';345++len;346}347}348}349
350if (closedir(dirptr) == -1) {351close(attrdirfd);352return -1;353}354} else {355close(attrdirfd);356return -1;357}358close(attrdirfd);359}360return len;361}
362
363int
364solaris_removexattr(const char *path, const char *key)365{
366int ret = -1;367int attrfd = -1;368char *mapped_path = NULL;369
370ret = solaris_xattr_resolve_path(path, &mapped_path);371if (!ret) {372attrfd = attropen(mapped_path, ".", O_RDONLY, 0);373} else {374attrfd = attropen(path, ".", O_RDONLY, 0);375}376if (attrfd >= 0) {377ret = unlinkat(attrfd, key, 0);378close(attrfd);379} else {380if (errno == ENOENT)381errno = ENODATA;382ret = -1;383}384
385GF_FREE(mapped_path);386
387return ret;388}
389
390int
391solaris_getxattr(const char *path, const char *key, char *value, size_t size)392{
393int attrfd = -1;394int ret = 0;395char *mapped_path = NULL;396
397ret = solaris_xattr_resolve_path(path, &mapped_path);398if (!ret) {399attrfd = attropen(mapped_path, key, O_RDONLY, 0);400} else {401attrfd = attropen(path, key, O_RDONLY, 0);402}403
404if (attrfd >= 0) {405if (size == 0) {406struct stat buf;407fstat(attrfd, &buf);408ret = buf.st_size;409} else {410ret = read(attrfd, value, size);411}412close(attrfd);413} else {414if (errno != ENOENT)415gf_msg("libglusterfs", GF_LOG_INFO, errno,416LG_MSG_READ_ATTRIBUTE_FAILED,417"Couldn't read "418"extended attribute for the file %s",419path);420if (errno == ENOENT)421errno = ENODATA;422ret = -1;423}424GF_FREE(mapped_path);425return ret;426}
427
428char *429strsep(char **str, const char *delims)430{
431char *token;432
433if (*str == NULL) {434/* No more tokens */435return NULL;436}437
438token = *str;439while (**str != '\0') {440if (strchr(delims, **str) != NULL) {441**str = '\0';442(*str)++;443return token;444}445(*str)++;446}447/* There is no other token */448*str = NULL;449return token;450}
451
452/* Code comes from libiberty */
453
454int
455vasprintf(char **result, const char *format, va_list args)456{
457return gf_vasprintf(result, format, args);458}
459
460int
461asprintf(char **buf, const char *fmt, ...)462{
463int status;464va_list ap;465
466va_start(ap, fmt);467status = vasprintf(buf, fmt, ap);468va_end(ap);469return status;470}
471
472int
473solaris_unlink(const char *path)474{
475char *mapped_path = NULL;476struct stat stbuf = {4770,478};479int ret = -1;480
481ret = solaris_xattr_resolve_path(path, &mapped_path);482
483if (!ret && mapped_path) {484if (lstat(path, &stbuf)) {485gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,486"Stat failed on "487"mapped file %s",488mapped_path);489goto out;490}491if (stbuf.st_nlink == 1) {492if (remove(mapped_path))493gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,494"Failed to "495"remove mapped file %s",496mapped_path);497}498}499
500out:501GF_FREE(mapped_path);502
503return unlink(path);504}
505
506int
507solaris_rename(const char *old_path, const char *new_path)508{
509char *mapped_path = NULL;510int ret = -1;511
512ret = solaris_xattr_resolve_path(new_path, &mapped_path);513
514if (!ret && mapped_path) {515if (!remove(mapped_path))516gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED,517"Failed to remove "518"mapped file %s.",519mapped_path);520GF_FREE(mapped_path);521}522
523return rename(old_path, new_path);524}
525
526char *527mkdtemp(char *tempstring)528{
529char *new_string = NULL;530int ret = 0;531
532new_string = mkstemp(tempstring);533if (!new_string)534goto out;535
536ret = mkdir(new_string, 0700);537if (ret < 0)538new_string = NULL;539
540out:541return new_string;542}
543
544#endif /* GF_SOLARIS_HOST_OS */545
546#ifdef GF_BSD_HOST_OS547void
548gf_extattr_list_reshape(char *bsd_list, ssize_t size)549{
550/*551* the format of bsd_list is
552* <attr_len>attr<attr_len>attr...
553* we try to reformat it as Linux's
554* attr<\0>attr<\0>...
555* */
556if (NULL == bsd_list || size <= 0)557return;558
559size_t i = 0, j;560
561while (i < size) {562size_t attr_len = bsd_list[i];563
564for (j = i; j < i + attr_len; ++j)565bsd_list[j] = bsd_list[j + 1];566bsd_list[j] = '\0';567
568i += attr_len + 1;569gf_msg_debug("syscall", 0, "syscall debug: %lu", attr_len);570}571}
572#endif /* GF_BSD_HOST_OS */573
574#ifndef HAVE_STRNLEN575size_t
576strnlen(const char *string, size_t maxlen)577{
578int len = 0;579while ((len < maxlen) && string[len])580len++;581return len;582}
583#endif /* STRNLEN */584
585int
586gf_umount_lazy(char *xlname, char *path, int rmdir_flag)587{
588int ret = -1;589runner_t runner = {5900,591};592
593runinit(&runner);594#ifdef GF_LINUX_HOST_OS595runner_add_args(&runner, _PATH_UMOUNT, "-l", path, NULL);596#else597if (rmdir_flag)598runner_add_args(&runner, SBIN_DIR "/umountd", "-r", path, NULL);599else600runner_add_args(&runner, SBIN_DIR "/umountd", path, NULL);601#endif602ret = runner_run(&runner);603if (ret) {604gf_msg(xlname, GF_LOG_ERROR, errno, LG_MSG_UNMOUNT_FAILED,605"Lazy unmount of %s", path);606}607
608#ifdef GF_LINUX_HOST_OS609if (!ret && rmdir_flag) {610ret = sys_rmdir(path);611if (ret)612gf_msg(xlname, GF_LOG_WARNING, errno, LG_MSG_DIR_OP_FAILED,613"rmdir %s", path);614}615#endif616
617return ret;618}
619