// -*- 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. * */ #ifndef CEPH_FILEPATH_H #define CEPH_FILEPATH_H /* * BUG: /a/b/c is equivalent to a/b/c in dentry-breakdown, but not string. * -> should it be different? how? should this[0] be "", with depth 4? * */ #include #include #include using namespace std; #include "buffer.h" #include "encoding.h" #include "include/types.h" #include "include/fs_types.h" #include "common/Formatter.h" class filepath { inodeno_t ino; // base inode. ino=0 implies pure relative path. string path; // relative path. /** bits - path segments * this is ['a', 'b', 'c'] for both the aboslute and relative case. * * NOTE: this value is LAZILY maintained... i.e. it's a cache */ mutable vector bits; bool encoded; void rebuild_path() { path.clear(); for (unsigned i=0; i 0) || encoded) { // skip empty components unless they were introduced deliberately // see commit message for more detail bits.push_back( path.substr(off,nextslash-off) ); } off = nextslash+1; } } public: filepath() : ino(0), encoded(false) { } filepath(const string& s, inodeno_t i) : ino(i), path(s), encoded(false) { } filepath(const char* s, inodeno_t i) : ino(i), path(s), encoded(false) { } filepath(const filepath& o) { ino = o.ino; path = o.path; bits = o.bits; encoded = o.encoded; } filepath(inodeno_t i) : ino(i), encoded(false) { } void set_path(const char *s, inodeno_t b) { path = s; ino = b; } /* * if we are fed a relative path as a string, either set ino=0 (strictly * relative) or 1 (absolute). throw out any leading '/'. */ filepath(const char *s) : encoded(false) { set_path(s); } void set_path(const char *s) { if (s[0] == '/') { path = s + 1; ino = 1; } else { ino = 0; path = s; } bits.clear(); } // accessors inodeno_t get_ino() const { return ino; } const string& get_path() const { return path; } const char *c_str() const { return path.c_str(); } int length() const { return path.length(); } unsigned depth() const { if (bits.empty() && path.length() > 0) parse_bits(); return bits.size(); } bool empty() const { return path.length() == 0 && ino == 0; } bool absolute() const { return ino == 1; } bool pure_relative() const { return ino == 0; } bool ino_relative() const { return ino > 0; } const string& operator[](int i) const { if (bits.empty() && path.length() > 0) parse_bits(); return bits[i]; } const string& last_dentry() const { if (bits.empty() && path.length() > 0) parse_bits(); assert(!bits.empty()); return bits[ bits.size()-1 ]; } filepath prefixpath(int s) const { filepath t(ino); for (int i=0; i 0) parse_bits(); bits.pop_back(); rebuild_path(); } void push_dentry(const string& s) { if (bits.empty() && path.length() > 0) parse_bits(); if (!bits.empty()) path += "/"; path += s; bits.push_back(s); } void push_dentry(const char *cs) { string s = cs; push_dentry(s); } void push_front_dentry(const string& s) { bits.insert(bits.begin(), s); rebuild_path(); } void append(const filepath& a) { assert(a.pure_relative()); for (unsigned i=0; idump_unsigned("base_ino", ino); f->dump_string("relative_path", path); } static void generate_test_instances(list& o) { o.push_back(new filepath); o.push_back(new filepath("/usr/bin", 0)); o.push_back(new filepath("/usr/sbin", 1)); o.push_back(new filepath("var/log", 1)); o.push_back(new filepath("foo/bar", 101)); } }; WRITE_CLASS_ENCODER(filepath) inline ostream& operator<<(ostream& out, const filepath& path) { if (path.get_ino()) { out << '#' << path.get_ino(); if (path.depth()) out << '/'; } return out << path.get_path(); } #endif