X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fos%2Ffilestore%2FLFNIndex.cc;fp=src%2Fceph%2Fsrc%2Fos%2Ffilestore%2FLFNIndex.cc;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=b3e451f62b1f5d51d2e000661b63772ab4efa9d5;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/os/filestore/LFNIndex.cc b/src/ceph/src/os/filestore/LFNIndex.cc deleted file mode 100644 index b3e451f..0000000 --- a/src/ceph/src/os/filestore/LFNIndex.cc +++ /dev/null @@ -1,1405 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2004-2006 Sage Weil - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include -#include -#include -#include -#include -#include - -#if defined(__FreeBSD__) -#include -#endif - -#include "osd/osd_types.h" -#include "include/object.h" -#include "common/config.h" -#include "common/debug.h" -#include "include/buffer.h" -#include "common/ceph_crypto.h" -#include "include/compat.h" -#include "chain_xattr.h" - -#include "LFNIndex.h" -using ceph::crypto::SHA1; - -#define dout_context cct -#define dout_subsys ceph_subsys_filestore -#undef dout_prefix -#define dout_prefix *_dout << "LFNIndex(" << get_base_path() << ") " - - -const string LFNIndex::LFN_ATTR = "user.cephos.lfn"; -const string LFNIndex::PHASH_ATTR_PREFIX = "user.cephos.phash."; -const string LFNIndex::SUBDIR_PREFIX = "DIR_"; -const string LFNIndex::FILENAME_COOKIE = "long"; -const int LFNIndex::FILENAME_PREFIX_LEN = FILENAME_SHORT_LEN - FILENAME_HASH_LEN - - FILENAME_COOKIE.size() - - FILENAME_EXTRA; -void LFNIndex::maybe_inject_failure() -{ - if (error_injection_enabled) { - if (current_failure > last_failure && - (((double)(rand() % 10000))/((double)(10000)) - < error_injection_probability)) { - last_failure = current_failure; - current_failure = 0; - throw RetryException(); - } - ++current_failure; - } -} - -// Helper to close fd's when we leave scope. This is useful when used -// in combination with RetryException, thrown by the above. -struct FDCloser { - int fd; - explicit FDCloser(int f) : fd(f) {} - ~FDCloser() { - VOID_TEMP_FAILURE_RETRY(::close(fd)); - } -}; - - -/* Public methods */ - -uint64_t LFNIndex::get_max_escaped_name_len(const hobject_t &obj) -{ - ghobject_t ghobj(obj); - ghobj.shard_id = shard_id_t(0); - ghobj.generation = 0; - ghobj.hobj.snap = 0; - return lfn_generate_object_name_current(ghobj).size(); -} - -int LFNIndex::init() -{ - return _init(); -} - -int LFNIndex::created(const ghobject_t &oid, const char *path) -{ - WRAP_RETRY( - vector path_comp; - string short_name; - r = decompose_full_path(path, &path_comp, 0, &short_name); - if (r < 0) - goto out; - r = lfn_created(path_comp, oid, short_name); - if (r < 0) { - if (failed) { - /* This is hacky, but the only way we get ENOENT from lfn_created here is - * if we did a failure injection in _created below AND actually started the - * split or merge. In that case, lfn_created already suceeded, and - * WRAP_RETRY already cleaned it up and we are actually done. In a real - * failure, the filestore itself would have ended up calling this with - * the new path, not the old one, so we'd find it. - */ - r = 0; - } - goto out; - } - r = _created(path_comp, oid, short_name); - if (r < 0) - goto out; - ); -} - -int LFNIndex::unlink(const ghobject_t &oid) -{ - WRAP_RETRY( - vector path; - string short_name; - r = _lookup(oid, &path, &short_name, NULL); - if (r < 0) { - goto out; - } - r = _remove(path, oid, short_name); - if (r < 0) { - goto out; - } - ); -} - -int LFNIndex::lookup(const ghobject_t &oid, - IndexedPath *out_path, - int *hardlink) -{ - WRAP_RETRY( - vector path; - string short_name; - r = _lookup(oid, &path, &short_name, hardlink); - if (r < 0) - goto out; - string full_path = get_full_path(path, short_name); - *out_path = std::make_shared(full_path, this); - r = 0; - ); -} - -int LFNIndex::pre_hash_collection(uint32_t pg_num, uint64_t expected_num_objs) -{ - return _pre_hash_collection(pg_num, expected_num_objs); -} - - -int LFNIndex::collection_list_partial(const ghobject_t &start, - const ghobject_t &end, - int max_count, - vector *ls, - ghobject_t *next) -{ - return _collection_list_partial(start, end, max_count, ls, next); -} - -/* Derived class utility methods */ - -int LFNIndex::fsync_dir(const vector &path) -{ - maybe_inject_failure(); - int fd = ::open(get_full_path_subdir(path).c_str(), O_RDONLY); - if (fd < 0) - return -errno; - FDCloser f(fd); - maybe_inject_failure(); - int r = ::fsync(fd); - maybe_inject_failure(); - if (r < 0) - return -errno; - else - return 0; -} - -int LFNIndex::link_object(const vector &from, - const vector &to, - const ghobject_t &oid, - const string &from_short_name) -{ - int r; - string from_path = get_full_path(from, from_short_name); - string to_path; - maybe_inject_failure(); - r = lfn_get_name(to, oid, 0, &to_path, 0); - if (r < 0) - return r; - maybe_inject_failure(); - r = ::link(from_path.c_str(), to_path.c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - else - return 0; -} - -int LFNIndex::remove_objects(const vector &dir, - const map &to_remove, - map *remaining) -{ - set clean_chains; - for (map::const_iterator to_clean = to_remove.begin(); - to_clean != to_remove.end(); - ++to_clean) { - if (!lfn_is_hashed_filename(to_clean->first)) { - maybe_inject_failure(); - int r = ::unlink(get_full_path(dir, to_clean->first).c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - continue; - } - if (clean_chains.count(lfn_get_short_name(to_clean->second, 0))) - continue; - set holes; - map > chain; - for (int i = 0; ; ++i) { - string short_name = lfn_get_short_name(to_clean->second, i); - if (remaining->count(short_name)) { - chain[i] = *(remaining->find(short_name)); - } else if (to_remove.count(short_name)) { - holes.insert(i); - } else { - break; - } - } - - map >::reverse_iterator candidate = chain.rbegin(); - for (set::iterator i = holes.begin(); - i != holes.end(); - ++i) { - if (candidate == chain.rend() || *i > candidate->first) { - string remove_path_name = - get_full_path(dir, lfn_get_short_name(to_clean->second, *i)); - maybe_inject_failure(); - int r = ::unlink(remove_path_name.c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - continue; - } - string from = get_full_path(dir, candidate->second.first); - string to = get_full_path(dir, lfn_get_short_name(candidate->second.second, *i)); - maybe_inject_failure(); - int r = ::rename(from.c_str(), to.c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - remaining->erase(candidate->second.first); - remaining->insert(pair( - lfn_get_short_name(candidate->second.second, *i), - candidate->second.second)); - ++candidate; - } - if (!holes.empty()) - clean_chains.insert(lfn_get_short_name(to_clean->second, 0)); - } - return 0; -} - -int LFNIndex::move_objects(const vector &from, - const vector &to) -{ - map to_move; - int r; - r = list_objects(from, 0, NULL, &to_move); - if (r < 0) - return r; - for (map::iterator i = to_move.begin(); - i != to_move.end(); - ++i) { - string from_path = get_full_path(from, i->first); - string to_path, to_name; - r = lfn_get_name(to, i->second, &to_name, &to_path, 0); - if (r < 0) - return r; - maybe_inject_failure(); - r = ::link(from_path.c_str(), to_path.c_str()); - if (r < 0 && errno != EEXIST) - return -errno; - maybe_inject_failure(); - r = lfn_created(to, i->second, to_name); - maybe_inject_failure(); - if (r < 0) - return r; - } - r = fsync_dir(to); - if (r < 0) - return r; - for (map::iterator i = to_move.begin(); - i != to_move.end(); - ++i) { - maybe_inject_failure(); - r = ::unlink(get_full_path(from, i->first).c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - } - return fsync_dir(from); -} - -int LFNIndex::remove_object(const vector &from, - const ghobject_t &oid) -{ - string short_name; - int r, exist; - maybe_inject_failure(); - r = get_mangled_name(from, oid, &short_name, &exist); - maybe_inject_failure(); - if (r < 0) - return r; - if (exist == 0) - return -ENOENT; - return lfn_unlink(from, oid, short_name); -} - -int LFNIndex::get_mangled_name(const vector &from, - const ghobject_t &oid, - string *mangled_name, int *hardlink) -{ - return lfn_get_name(from, oid, mangled_name, 0, hardlink); -} - -int LFNIndex::move_subdir( - LFNIndex &from, - LFNIndex &dest, - const vector &path, - string dir - ) -{ - vector sub_path(path.begin(), path.end()); - sub_path.push_back(dir); - string from_path(from.get_full_path_subdir(sub_path)); - string to_path(dest.get_full_path_subdir(sub_path)); - int r = ::rename(from_path.c_str(), to_path.c_str()); - if (r < 0) - return -errno; - return 0; -} - -int LFNIndex::move_object( - LFNIndex &from, - LFNIndex &dest, - const vector &path, - const pair &obj - ) -{ - string from_path(from.get_full_path(path, obj.first)); - string to_path; - string to_name; - int exists; - int r = dest.lfn_get_name(path, obj.second, &to_name, &to_path, &exists); - if (r < 0) - return r; - if (!exists) { - r = ::link(from_path.c_str(), to_path.c_str()); - if (r < 0) - return r; - } - r = dest.lfn_created(path, obj.second, to_name); - if (r < 0) - return r; - r = dest.fsync_dir(path); - if (r < 0) - return r; - r = from.remove_object(path, obj.second); - if (r < 0) - return r; - return from.fsync_dir(path); -} - - -static int get_hobject_from_oinfo(const char *dir, const char *file, - ghobject_t *o) -{ - char path[PATH_MAX]; - snprintf(path, sizeof(path), "%s/%s", dir, file); - // Hack, user.ceph._ is the attribute used to store the object info - bufferptr bp; - int r = chain_getxattr_buf( - path, - "user.ceph._", - &bp); - if (r < 0) - return r; - bufferlist bl; - if (r > 0) - bl.push_back(bp); - object_info_t oi(bl); - *o = ghobject_t(oi.soid); - return 0; -} - - -int LFNIndex::list_objects(const vector &to_list, int max_objs, - long *handle, map *out) -{ - string to_list_path = get_full_path_subdir(to_list); - DIR *dir = ::opendir(to_list_path.c_str()); - if (!dir) { - return -errno; - } - - if (handle && *handle) { - seekdir(dir, *handle); - } - - struct dirent *de = nullptr; - int r = 0; - int listed = 0; - bool end = true; - while ((de = ::readdir(dir))) { - end = false; - if (max_objs > 0 && listed >= max_objs) { - break; - } - if (de->d_name[0] == '.') - continue; - string short_name(de->d_name); - ghobject_t obj; - if (lfn_is_object(short_name)) { - r = lfn_translate(to_list, short_name, &obj); - if (r == -EINVAL) { - continue; - } else if (r < 0) { - goto cleanup; - } else { - string long_name = lfn_generate_object_name(obj); - if (!lfn_must_hash(long_name)) { - assert(long_name == short_name); - } - if (index_version == HASH_INDEX_TAG) - get_hobject_from_oinfo(to_list_path.c_str(), short_name.c_str(), &obj); - - out->insert(pair(short_name, obj)); - ++listed; - } - } - } - - if (handle && !end) { - *handle = telldir(dir); - } - - r = 0; - cleanup: - ::closedir(dir); - return r; -} - -int LFNIndex::list_subdirs(const vector &to_list, - vector *out) -{ - string to_list_path = get_full_path_subdir(to_list); - DIR *dir = ::opendir(to_list_path.c_str()); - if (!dir) - return -errno; - - struct dirent *de = nullptr; - while ((de = ::readdir(dir))) { - string short_name(de->d_name); - string demangled_name; - if (lfn_is_subdir(short_name, &demangled_name)) { - out->push_back(demangled_name); - } - } - - ::closedir(dir); - return 0; -} - -int LFNIndex::create_path(const vector &to_create) -{ - maybe_inject_failure(); - int r = ::mkdir(get_full_path_subdir(to_create).c_str(), 0777); - maybe_inject_failure(); - if (r < 0) - return -errno; - else - return 0; -} - -int LFNIndex::remove_path(const vector &to_remove) -{ - maybe_inject_failure(); - int r = ::rmdir(get_full_path_subdir(to_remove).c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - else - return 0; -} - -int LFNIndex::path_exists(const vector &to_check, int *exists) -{ - string full_path = get_full_path_subdir(to_check); - struct stat buf; - if (::stat(full_path.c_str(), &buf)) { - int r = -errno; - if (r == -ENOENT) { - *exists = 0; - return 0; - } else { - return r; - } - } else { - *exists = 1; - return 0; - } -} - -int LFNIndex::add_attr_path(const vector &path, - const string &attr_name, - bufferlist &attr_value) -{ - string full_path = get_full_path_subdir(path); - maybe_inject_failure(); - return chain_setxattr( - full_path.c_str(), mangle_attr_name(attr_name).c_str(), - reinterpret_cast(attr_value.c_str()), - attr_value.length()); -} - -int LFNIndex::get_attr_path(const vector &path, - const string &attr_name, - bufferlist &attr_value) -{ - string full_path = get_full_path_subdir(path); - bufferptr bp; - int r = chain_getxattr_buf( - full_path.c_str(), - mangle_attr_name(attr_name).c_str(), - &bp); - if (r > 0) - attr_value.push_back(bp); - return r; -} - -int LFNIndex::remove_attr_path(const vector &path, - const string &attr_name) -{ - string full_path = get_full_path_subdir(path); - string mangled_attr_name = mangle_attr_name(attr_name); - maybe_inject_failure(); - return chain_removexattr(full_path.c_str(), mangled_attr_name.c_str()); -} - -string LFNIndex::lfn_generate_object_name_keyless(const ghobject_t &oid) -{ - char s[FILENAME_MAX_LEN]; - char *end = s + sizeof(s); - char *t = s; - - assert(oid.generation == ghobject_t::NO_GEN); - const char *i = oid.hobj.oid.name.c_str(); - // Escape subdir prefix - if (oid.hobj.oid.name.substr(0, 4) == "DIR_") { - *t++ = '\\'; - *t++ = 'd'; - i += 4; - } - while (*i && t < end) { - if (*i == '\\') { - *t++ = '\\'; - *t++ = '\\'; - } else if (*i == '.' && i == oid.hobj.oid.name.c_str()) { // only escape leading . - *t++ = '\\'; - *t++ = '.'; - } else if (*i == '/') { - *t++ = '\\'; - *t++ = 's'; - } else - *t++ = *i; - i++; - } - - if (oid.hobj.snap == CEPH_NOSNAP) - t += snprintf(t, end - t, "_head"); - else if (oid.hobj.snap == CEPH_SNAPDIR) - t += snprintf(t, end - t, "_snapdir"); - else - t += snprintf(t, end - t, "_%llx", (long long unsigned)oid.hobj.snap); - snprintf(t, end - t, "_%.*X", (int)(sizeof(oid.hobj.get_hash())*2), oid.hobj.get_hash()); - - return string(s); -} - -static void append_escaped(string::const_iterator begin, - string::const_iterator end, - string *out) -{ - for (string::const_iterator i = begin; i != end; ++i) { - if (*i == '\\') { - out->append("\\\\"); - } else if (*i == '/') { - out->append("\\s"); - } else if (*i == '_') { - out->append("\\u"); - } else if (*i == '\0') { - out->append("\\n"); - } else { - out->append(i, i+1); - } - } -} - -string LFNIndex::lfn_generate_object_name_current(const ghobject_t &oid) -{ - string full_name; - string::const_iterator i = oid.hobj.oid.name.begin(); - if (oid.hobj.oid.name.substr(0, 4) == "DIR_") { - full_name.append("\\d"); - i += 4; - } else if (oid.hobj.oid.name[0] == '.') { - full_name.append("\\."); - ++i; - } - append_escaped(i, oid.hobj.oid.name.end(), &full_name); - full_name.append("_"); - append_escaped(oid.hobj.get_key().begin(), oid.hobj.get_key().end(), &full_name); - full_name.append("_"); - - char buf[PATH_MAX]; - char *t = buf; - const char *end = t + sizeof(buf); - if (oid.hobj.snap == CEPH_NOSNAP) - t += snprintf(t, end - t, "head"); - else if (oid.hobj.snap == CEPH_SNAPDIR) - t += snprintf(t, end - t, "snapdir"); - else - t += snprintf(t, end - t, "%llx", (long long unsigned)oid.hobj.snap); - t += snprintf(t, end - t, "_%.*X", (int)(sizeof(oid.hobj.get_hash())*2), oid.hobj.get_hash()); - full_name.append(buf, t); - full_name.append("_"); - - append_escaped(oid.hobj.nspace.begin(), oid.hobj.nspace.end(), &full_name); - full_name.append("_"); - - t = buf; - if (oid.hobj.pool == -1) - t += snprintf(t, end - t, "none"); - else - t += snprintf(t, end - t, "%llx", (long long unsigned)oid.hobj.pool); - full_name.append(buf, t); - - if (oid.generation != ghobject_t::NO_GEN || - oid.shard_id != shard_id_t::NO_SHARD) { - full_name.append("_"); - - t = buf; - t += snprintf(t, end - buf, "%llx", (long long unsigned)oid.generation); - full_name.append(buf, t); - - full_name.append("_"); - - t = buf; - t += snprintf(t, end - buf, "%x", (int)oid.shard_id); - full_name.append(buf, t); - } - - return full_name; -} - -string LFNIndex::lfn_generate_object_name_poolless(const ghobject_t &oid) -{ - if (index_version == HASH_INDEX_TAG) - return lfn_generate_object_name_keyless(oid); - - assert(oid.generation == ghobject_t::NO_GEN); - string full_name; - string::const_iterator i = oid.hobj.oid.name.begin(); - if (oid.hobj.oid.name.substr(0, 4) == "DIR_") { - full_name.append("\\d"); - i += 4; - } else if (oid.hobj.oid.name[0] == '.') { - full_name.append("\\."); - ++i; - } - append_escaped(i, oid.hobj.oid.name.end(), &full_name); - full_name.append("_"); - append_escaped(oid.hobj.get_key().begin(), oid.hobj.get_key().end(), &full_name); - full_name.append("_"); - - char snap_with_hash[PATH_MAX]; - char *t = snap_with_hash; - char *end = t + sizeof(snap_with_hash); - if (oid.hobj.snap == CEPH_NOSNAP) - t += snprintf(t, end - t, "head"); - else if (oid.hobj.snap == CEPH_SNAPDIR) - t += snprintf(t, end - t, "snapdir"); - else - t += snprintf(t, end - t, "%llx", (long long unsigned)oid.hobj.snap); - snprintf(t, end - t, "_%.*X", (int)(sizeof(oid.hobj.get_hash())*2), oid.hobj.get_hash()); - full_name += string(snap_with_hash); - return full_name; -} - -int LFNIndex::lfn_get_name(const vector &path, - const ghobject_t &oid, - string *mangled_name, string *out_path, - int *hardlink) -{ - string full_name = lfn_generate_object_name(oid); - int r; - - if (!lfn_must_hash(full_name)) { - if (mangled_name) - *mangled_name = full_name; - if (out_path) - *out_path = get_full_path(path, full_name); - if (hardlink) { - struct stat buf; - string full_path = get_full_path(path, full_name); - maybe_inject_failure(); - r = ::stat(full_path.c_str(), &buf); - if (r < 0) { - if (errno == ENOENT) - *hardlink = 0; - else - return -errno; - } else { - *hardlink = buf.st_nlink; - } - } - return 0; - } - - int i = 0; - string candidate; - string candidate_path; - for ( ; ; ++i) { - candidate = lfn_get_short_name(oid, i); - candidate_path = get_full_path(path, candidate); - bufferptr bp; - r = chain_getxattr_buf( - candidate_path.c_str(), - get_lfn_attr().c_str(), - &bp); - if (r < 0) { - if (errno != ENODATA && errno != ENOENT) - return -errno; - if (errno == ENODATA) { - // Left over from incomplete transaction, it'll be replayed - maybe_inject_failure(); - r = ::unlink(candidate_path.c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - } - if (mangled_name) - *mangled_name = candidate; - if (out_path) - *out_path = candidate_path; - if (hardlink) - *hardlink = 0; - return 0; - } - assert(r > 0); - string lfn(bp.c_str(), bp.length()); - if (lfn == full_name) { - if (mangled_name) - *mangled_name = candidate; - if (out_path) - *out_path = candidate_path; - if (hardlink) { - struct stat st; - r = ::stat(candidate_path.c_str(), &st); - if (r < 0) { - if (errno == ENOENT) - *hardlink = 0; - else - return -errno; - } else { - *hardlink = st.st_nlink; - } - } - return 0; - } - bp = bufferptr(); - r = chain_getxattr_buf( - candidate_path.c_str(), - get_alt_lfn_attr().c_str(), - &bp); - if (r > 0) { - // only consider alt name if nlink > 1 - struct stat st; - int rc = ::stat(candidate_path.c_str(), &st); - if (rc < 0) - return -errno; - if (st.st_nlink <= 1) { - // left over from incomplete unlink, remove - maybe_inject_failure(); - dout(20) << __func__ << " found extra alt attr for " << candidate_path - << ", long name " << string(bp.c_str(), bp.length()) << dendl; - rc = chain_removexattr(candidate_path.c_str(), - get_alt_lfn_attr().c_str()); - maybe_inject_failure(); - if (rc < 0) - return rc; - continue; - } - string lfn(bp.c_str(), bp.length()); - if (lfn == full_name) { - dout(20) << __func__ << " used alt attr for " << full_name << dendl; - if (mangled_name) - *mangled_name = candidate; - if (out_path) - *out_path = candidate_path; - if (hardlink) - *hardlink = st.st_nlink; - return 0; - } - } - } - ceph_abort(); // Unreachable - return 0; -} - -int LFNIndex::lfn_created(const vector &path, - const ghobject_t &oid, - const string &mangled_name) -{ - if (!lfn_is_hashed_filename(mangled_name)) - return 0; - string full_path = get_full_path(path, mangled_name); - string full_name = lfn_generate_object_name(oid); - maybe_inject_failure(); - - // if the main attr exists and is different, move it to the alt attr. - bufferptr bp; - int r = chain_getxattr_buf( - full_path.c_str(), - get_lfn_attr().c_str(), - &bp); - if (r > 0) { - string lfn(bp.c_str(), bp.length()); - if (lfn != full_name) { - dout(20) << __func__ << " " << mangled_name - << " moving old name to alt attr " - << lfn - << ", new name is " << full_name << dendl; - r = chain_setxattr( - full_path.c_str(), get_alt_lfn_attr().c_str(), - bp.c_str(), bp.length()); - if (r < 0) - return r; - } - } - - return chain_setxattr( - full_path.c_str(), get_lfn_attr().c_str(), - full_name.c_str(), full_name.size()); -} - -int LFNIndex::lfn_unlink(const vector &path, - const ghobject_t &oid, - const string &mangled_name) -{ - if (!lfn_is_hashed_filename(mangled_name)) { - string full_path = get_full_path(path, mangled_name); - maybe_inject_failure(); - int r = ::unlink(full_path.c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - return 0; - } - - int i = 0; - for ( ; ; ++i) { - string candidate = lfn_get_short_name(oid, i); - if (candidate == mangled_name) - break; - } - int removed_index = i; - ++i; - for ( ; ; ++i) { - struct stat buf; - string to_check = lfn_get_short_name(oid, i); - string to_check_path = get_full_path(path, to_check); - int r = ::stat(to_check_path.c_str(), &buf); - if (r < 0) { - if (errno == ENOENT) { - break; - } else { - return -errno; - } - } - } - string full_path = get_full_path(path, mangled_name); - int fd = ::open(full_path.c_str(), O_RDONLY); - if (fd < 0) - return -errno; - FDCloser f(fd); - if (i == removed_index + 1) { - maybe_inject_failure(); - int r = ::unlink(full_path.c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - } else { - string& rename_to = full_path; - string rename_from = get_full_path(path, lfn_get_short_name(oid, i - 1)); - maybe_inject_failure(); - int r = ::rename(rename_from.c_str(), rename_to.c_str()); - maybe_inject_failure(); - if (r < 0) - return -errno; - } - struct stat st; - int r = ::fstat(fd, &st); - if (r == 0 && st.st_nlink > 0) { - // remove alt attr - dout(20) << __func__ << " removing alt attr from " << full_path << dendl; - fsync_dir(path); - chain_fremovexattr(fd, get_alt_lfn_attr().c_str()); - } - return r; -} - -int LFNIndex::lfn_translate(const vector &path, - const string &short_name, - ghobject_t *out) -{ - if (!lfn_is_hashed_filename(short_name)) { - return lfn_parse_object_name(short_name, out); - } - string full_path = get_full_path(path, short_name); - // First, check alt attr - bufferptr bp; - int r = chain_getxattr_buf( - full_path.c_str(), - get_alt_lfn_attr().c_str(), - &bp); - if (r > 0) { - // There is an alt attr, does it match? - string lfn(bp.c_str(), bp.length()); - if (short_name_matches(short_name.c_str(), lfn.c_str())) { - return lfn_parse_object_name(lfn, out); - } - } - - // Get lfn_attr - bp = bufferptr(); - r = chain_getxattr_buf( - full_path.c_str(), - get_lfn_attr().c_str(), - &bp); - if (r < 0) - return r; - if (r == 0) - return -EINVAL; - - string long_name(bp.c_str(), bp.length()); - return lfn_parse_object_name(long_name, out); -} - -bool LFNIndex::lfn_is_object(const string &short_name) -{ - return lfn_is_hashed_filename(short_name) || !lfn_is_subdir(short_name, 0); -} - -bool LFNIndex::lfn_is_subdir(const string &name, string *demangled) -{ - if (name.substr(0, SUBDIR_PREFIX.size()) == SUBDIR_PREFIX) { - if (demangled) - *demangled = demangle_path_component(name); - return 1; - } - return 0; -} - -static int parse_object(const char *s, ghobject_t& o) -{ - const char *hash = s + strlen(s) - 1; - while (*hash != '_' && - hash > s) - hash--; - const char *bar = hash - 1; - while (*bar != '_' && - bar > s) - bar--; - if (*bar == '_') { - char buf[bar-s + 1]; - char *t = buf; - const char *i = s; - while (i < bar) { - if (*i == '\\') { - i++; - switch (*i) { - case '\\': *t++ = '\\'; break; - case '.': *t++ = '.'; break; - case 's': *t++ = '/'; break; - case 'd': { - *t++ = 'D'; - *t++ = 'I'; - *t++ = 'R'; - *t++ = '_'; - break; - } - default: ceph_abort(); - } - } else { - *t++ = *i; - } - i++; - } - *t = 0; - o.hobj.oid.name = string(buf, t-buf); - if (strncmp(bar+1, "head", 4) == 0) - o.hobj.snap = CEPH_NOSNAP; - else if (strncmp(bar+1, "snapdir", 7) == 0) - o.hobj.snap = CEPH_SNAPDIR; - else - o.hobj.snap = strtoull(bar+1, NULL, 16); - - uint32_t hobject_hash_input; - sscanf(hash, "_%X", &hobject_hash_input); - o.hobj.set_hash(hobject_hash_input); - - return 1; - } - return 0; -} - -int LFNIndex::lfn_parse_object_name_keyless(const string &long_name, ghobject_t *out) -{ - int r = parse_object(long_name.c_str(), *out); - int64_t pool = -1; - spg_t pg; - if (coll().is_pg_prefix(&pg)) - pool = (int64_t)pg.pgid.pool(); - out->hobj.pool = pool; - if (!r) return -EINVAL; - string temp = lfn_generate_object_name(*out); - return r ? 0 : -EINVAL; -} - -static bool append_unescaped(string::const_iterator begin, - string::const_iterator end, - string *out) -{ - for (string::const_iterator i = begin; i != end; ++i) { - if (*i == '\\') { - ++i; - if (*i == '\\') - out->append("\\"); - else if (*i == 's') - out->append("/"); - else if (*i == 'n') - (*out) += '\0'; - else if (*i == 'u') - out->append("_"); - else - return false; - } else { - out->append(i, i+1); - } - } - return true; -} - -int LFNIndex::lfn_parse_object_name_poolless(const string &long_name, - ghobject_t *out) -{ - string name; - string key; - uint32_t hash; - snapid_t snap; - - string::const_iterator current = long_name.begin(); - if (*current == '\\') { - ++current; - if (current == long_name.end()) { - return -EINVAL; - } else if (*current == 'd') { - name.append("DIR_"); - ++current; - } else if (*current == '.') { - name.append("."); - ++current; - } else { - --current; - } - } - - string::const_iterator end = current; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - if (!append_unescaped(current, end, &name)) - return -EINVAL; - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - if (!append_unescaped(current, end, &key)) - return -EINVAL; - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - string snap_str(current, end); - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end != long_name.end()) - return -EINVAL; - string hash_str(current, end); - - if (snap_str == "head") - snap = CEPH_NOSNAP; - else if (snap_str == "snapdir") - snap = CEPH_SNAPDIR; - else - snap = strtoull(snap_str.c_str(), NULL, 16); - sscanf(hash_str.c_str(), "%X", &hash); - - - int64_t pool = -1; - spg_t pg; - if (coll().is_pg_prefix(&pg)) - pool = (int64_t)pg.pgid.pool(); - (*out) = ghobject_t(hobject_t(name, key, snap, hash, pool, "")); - return 0; -} - - -int LFNIndex::lfn_parse_object_name(const string &long_name, ghobject_t *out) -{ - string name; - string key; - string ns; - uint32_t hash; - snapid_t snap; - uint64_t pool; - gen_t generation = ghobject_t::NO_GEN; - shard_id_t shard_id = shard_id_t::NO_SHARD; - - if (index_version == HASH_INDEX_TAG) - return lfn_parse_object_name_keyless(long_name, out); - if (index_version == HASH_INDEX_TAG_2) - return lfn_parse_object_name_poolless(long_name, out); - - string::const_iterator current = long_name.begin(); - if (*current == '\\') { - ++current; - if (current == long_name.end()) { - return -EINVAL; - } else if (*current == 'd') { - name.append("DIR_"); - ++current; - } else if (*current == '.') { - name.append("."); - ++current; - } else { - --current; - } - } - - string::const_iterator end = current; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - if (!append_unescaped(current, end, &name)) - return -EINVAL; - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - if (!append_unescaped(current, end, &key)) - return -EINVAL; - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - string snap_str(current, end); - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - string hash_str(current, end); - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - if (!append_unescaped(current, end, &ns)) - return -EINVAL; - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - string pstring(current, end); - - // Optional generation/shard_id - string genstring, shardstring; - if (end != long_name.end()) { - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end == long_name.end()) - return -EINVAL; - genstring = string(current, end); - - generation = (gen_t)strtoull(genstring.c_str(), NULL, 16); - - current = ++end; - for ( ; end != long_name.end() && *end != '_'; ++end) ; - if (end != long_name.end()) - return -EINVAL; - shardstring = string(current, end); - - shard_id = (shard_id_t)strtoul(shardstring.c_str(), NULL, 16); - } - - if (snap_str == "head") - snap = CEPH_NOSNAP; - else if (snap_str == "snapdir") - snap = CEPH_SNAPDIR; - else - snap = strtoull(snap_str.c_str(), NULL, 16); - sscanf(hash_str.c_str(), "%X", &hash); - - if (pstring == "none") - pool = (uint64_t)-1; - else - pool = strtoull(pstring.c_str(), NULL, 16); - - (*out) = ghobject_t(hobject_t(name, key, snap, hash, (int64_t)pool, ns), generation, shard_id); - return 0; -} - -bool LFNIndex::lfn_is_hashed_filename(const string &name) -{ - if (name.size() < (unsigned)FILENAME_SHORT_LEN) { - return 0; - } - if (name.substr(name.size() - FILENAME_COOKIE.size(), FILENAME_COOKIE.size()) - == FILENAME_COOKIE) { - return 1; - } else { - return 0; - } -} - -bool LFNIndex::lfn_must_hash(const string &long_name) -{ - return (int)long_name.size() >= FILENAME_SHORT_LEN; -} - -static inline void buf_to_hex(const unsigned char *buf, int len, char *str) -{ - int i; - str[0] = '\0'; - for (i = 0; i < len; i++) { - sprintf(&str[i*2], "%02x", (int)buf[i]); - } -} - -int LFNIndex::hash_filename(const char *filename, char *hash, int buf_len) -{ - if (buf_len < FILENAME_HASH_LEN + 1) - return -EINVAL; - - char buf[FILENAME_LFN_DIGEST_SIZE]; - char hex[FILENAME_LFN_DIGEST_SIZE * 2]; - - SHA1 h; - h.Update((const byte *)filename, strlen(filename)); - h.Final((byte *)buf); - - buf_to_hex((byte *)buf, (FILENAME_HASH_LEN + 1) / 2, hex); - strncpy(hash, hex, FILENAME_HASH_LEN); - hash[FILENAME_HASH_LEN] = '\0'; - return 0; -} - -void LFNIndex::build_filename(const char *old_filename, int i, char *filename, int len) -{ - char hash[FILENAME_HASH_LEN + 1]; - - assert(len >= FILENAME_SHORT_LEN + 4); - - strncpy(filename, old_filename, FILENAME_PREFIX_LEN); - filename[FILENAME_PREFIX_LEN] = '\0'; - if ((int)strlen(filename) < FILENAME_PREFIX_LEN) - return; - if (old_filename[FILENAME_PREFIX_LEN] == '\0') - return; - - hash_filename(old_filename, hash, sizeof(hash)); - int ofs = FILENAME_PREFIX_LEN; - while (1) { - int suffix_len = sprintf(filename + ofs, "_%s_%d_%s", hash, i, FILENAME_COOKIE.c_str()); - if (ofs + suffix_len <= FILENAME_SHORT_LEN || !ofs) - break; - ofs--; - } -} - -bool LFNIndex::short_name_matches(const char *short_name, const char *cand_long_name) -{ - const char *end = short_name; - while (*end) ++end; - const char *suffix = end; - if (suffix > short_name) --suffix; // last char - while (suffix > short_name && *suffix != '_') --suffix; // back to first _ - if (suffix > short_name) --suffix; // one behind that - while (suffix > short_name && *suffix != '_') --suffix; // back to second _ - - int index = -1; - char buf[FILENAME_SHORT_LEN + 4]; - assert((end - suffix) < (int)sizeof(buf)); - int r = sscanf(suffix, "_%d_%s", &index, buf); - if (r < 2) - return false; - if (strcmp(buf, FILENAME_COOKIE.c_str()) != 0) - return false; - build_filename(cand_long_name, index, buf, sizeof(buf)); - return strcmp(short_name, buf) == 0; -} - -string LFNIndex::lfn_get_short_name(const ghobject_t &oid, int i) -{ - string long_name = lfn_generate_object_name(oid); - assert(lfn_must_hash(long_name)); - char buf[FILENAME_SHORT_LEN + 4]; - build_filename(long_name.c_str(), i, buf, sizeof(buf)); - return string(buf); -} - -const string &LFNIndex::get_base_path() -{ - return base_path; -} - -string LFNIndex::get_full_path_subdir(const vector &rel) -{ - string retval = get_base_path(); - for (vector::const_iterator i = rel.begin(); - i != rel.end(); - ++i) { - retval += "/"; - retval += mangle_path_component(*i); - } - return retval; -} - -string LFNIndex::get_full_path(const vector &rel, const string &name) -{ - return get_full_path_subdir(rel) + "/" + name; -} - -string LFNIndex::mangle_path_component(const string &component) -{ - return SUBDIR_PREFIX + component; -} - -string LFNIndex::demangle_path_component(const string &component) -{ - return component.substr(SUBDIR_PREFIX.size(), component.size() - SUBDIR_PREFIX.size()); -} - -int LFNIndex::decompose_full_path(const char *in, vector *out, - ghobject_t *oid, string *shortname) -{ - const char *beginning = in + get_base_path().size(); - const char *end = beginning; - while (1) { - end++; - beginning = end++; - for ( ; *end != '\0' && *end != '/'; ++end) ; - if (*end != '\0') { - out->push_back(demangle_path_component(string(beginning, end - beginning))); - continue; - } else { - break; - } - } - *shortname = string(beginning, end - beginning); - if (oid) { - int r = lfn_translate(*out, *shortname, oid); - if (r < 0) - return r; - } - return 0; -} - -string LFNIndex::mangle_attr_name(const string &attr) -{ - return PHASH_ATTR_PREFIX + attr; -}