Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / include / filepath.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software 
11  * Foundation.  See file COPYING.
12  * 
13  */
14
15
16 #ifndef CEPH_FILEPATH_H
17 #define CEPH_FILEPATH_H
18
19 /*
20  * BUG:  /a/b/c is equivalent to a/b/c in dentry-breakdown, but not string.
21  *   -> should it be different?  how?  should this[0] be "", with depth 4?
22  *
23  */
24
25
26 #include <iosfwd>
27 #include <string>
28 #include <vector>
29 using namespace std;
30
31 #include "buffer.h"
32 #include "encoding.h"
33 #include "include/types.h"
34 #include "include/fs_types.h"
35
36 #include "common/Formatter.h"
37
38
39 class filepath {
40   inodeno_t ino;   // base inode.  ino=0 implies pure relative path.
41   string path;     // relative path.
42
43   /** bits - path segments
44    * this is ['a', 'b', 'c'] for both the aboslute and relative case.
45    *
46    * NOTE: this value is LAZILY maintained... i.e. it's a cache
47    */
48   mutable vector<string> bits;
49   bool encoded;
50
51   void rebuild_path() {
52     path.clear();
53     for (unsigned i=0; i<bits.size(); i++) {
54       if (i) path += "/";
55       path += bits[i];
56     }
57   }
58   void parse_bits() const {
59     bits.clear();
60     int off = 0;
61     while (off < (int)path.length()) {
62       int nextslash = path.find('/', off);
63       if (nextslash < 0) 
64         nextslash = path.length();  // no more slashes
65       if (((nextslash - off) > 0) || encoded) {
66         // skip empty components unless they were introduced deliberately
67         // see commit message for more detail
68         bits.push_back( path.substr(off,nextslash-off) );
69       }
70       off = nextslash+1;
71     }
72   }
73
74  public:
75   filepath() : ino(0), encoded(false) { }
76   filepath(const string& s, inodeno_t i) : ino(i), path(s), encoded(false) { }
77   filepath(const char* s, inodeno_t i) : ino(i), path(s), encoded(false) { }
78   filepath(const filepath& o) {
79     ino = o.ino;
80     path = o.path;
81     bits = o.bits;
82     encoded = o.encoded;
83   }
84   filepath(inodeno_t i) : ino(i), encoded(false) { }
85   
86   void set_path(const char *s, inodeno_t b) {
87     path = s;
88     ino = b;
89   }
90
91   /*
92    * if we are fed a relative path as a string, either set ino=0 (strictly
93    * relative) or 1 (absolute).  throw out any leading '/'.
94    */
95   filepath(const char *s) : encoded(false) {
96     set_path(s);
97   }
98   void set_path(const char *s) {
99     if (s[0] == '/') {
100       path = s + 1;    
101       ino = 1;
102     } else {
103       ino = 0;
104       path = s;
105     }
106     bits.clear();
107   }
108
109
110   // accessors
111   inodeno_t get_ino() const { return ino; }
112   const string& get_path() const { return path; }
113   const char *c_str() const { return path.c_str(); }
114
115   int length() const { return path.length(); }
116   unsigned depth() const {
117     if (bits.empty() && path.length() > 0) parse_bits();
118     return bits.size();
119   }
120   bool empty() const { return path.length() == 0 && ino == 0; }
121
122   bool absolute() const { return ino == 1; }
123   bool pure_relative() const { return ino == 0; }
124   bool ino_relative() const { return ino > 0; }
125   
126   const string& operator[](int i) const {
127     if (bits.empty() && path.length() > 0) parse_bits();
128     return bits[i];
129   }
130
131   const string& last_dentry() const {
132     if (bits.empty() && path.length() > 0) parse_bits();
133     assert(!bits.empty());
134     return bits[ bits.size()-1 ];
135   }
136
137   filepath prefixpath(int s) const {
138     filepath t(ino);
139     for (int i=0; i<s; i++)
140       t.push_dentry(bits[i]);
141     return t;
142   }
143   filepath postfixpath(int s) const {
144     filepath t;
145     for (unsigned i=s; i<bits.size(); i++)
146       t.push_dentry(bits[i]);
147     return t;
148   }
149
150
151   // modifiers
152   //  string can be relative "a/b/c" (ino=0) or absolute "/a/b/c" (ino=1)
153   void _set_ino(inodeno_t i) { ino = i; }
154   void clear() {
155     ino = 0;
156     path = "";
157     bits.clear();
158   }
159
160   void pop_dentry() {
161     if (bits.empty() && path.length() > 0) 
162       parse_bits();
163     bits.pop_back();
164     rebuild_path();
165   }    
166   void push_dentry(const string& s) {
167     if (bits.empty() && path.length() > 0) 
168       parse_bits();
169     if (!bits.empty())
170       path += "/";
171     path += s;
172     bits.push_back(s);
173   }
174   void push_dentry(const char *cs) {
175     string s = cs;
176     push_dentry(s);
177   }
178   void push_front_dentry(const string& s) {
179     bits.insert(bits.begin(), s);
180     rebuild_path();
181   }
182   void append(const filepath& a) {
183     assert(a.pure_relative());
184     for (unsigned i=0; i<a.depth(); i++) 
185       push_dentry(a[i]);
186   }
187
188   // encoding
189   void encode(bufferlist& bl) const {
190     __u8 struct_v = 1;
191     ::encode(struct_v, bl);
192     ::encode(ino, bl);
193     ::encode(path, bl);
194   }
195   void decode(bufferlist::iterator& blp) {
196     bits.clear();
197     __u8 struct_v;
198     ::decode(struct_v, blp);
199     ::decode(ino, blp);
200     ::decode(path, blp);
201     encoded = true;
202   }
203   void dump(Formatter *f) const {
204     f->dump_unsigned("base_ino", ino);
205     f->dump_string("relative_path", path);
206   }
207   static void generate_test_instances(list<filepath*>& o) {
208     o.push_back(new filepath);
209     o.push_back(new filepath("/usr/bin", 0));
210     o.push_back(new filepath("/usr/sbin", 1));
211     o.push_back(new filepath("var/log", 1));
212     o.push_back(new filepath("foo/bar", 101));
213   }
214 };
215
216 WRITE_CLASS_ENCODER(filepath)
217
218 inline ostream& operator<<(ostream& out, const filepath& path)
219 {
220   if (path.get_ino()) {
221     out << '#' << path.get_ino();
222     if (path.depth())
223       out << '/';
224   }
225   return out << path.get_path();
226 }
227
228 #endif