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 <string_view>
29 #include <vector>
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(std::string_view s, inodeno_t i) : ino(i), path(s), encoded(false) { }
77 filepath(const string& s, inodeno_t i) : ino(i), path(s), encoded(false) { }
78 filepath(const char* s, inodeno_t i) : ino(i), path(s), encoded(false) { }
79 filepath(const filepath& o) {
80 ino = o.ino;
81 path = o.path;
82 bits = o.bits;
83 encoded = o.encoded;
84 }
85 filepath(inodeno_t i) : ino(i), encoded(false) { }
86
87 /*
88 * if we are fed a relative path as a string, either set ino=0 (strictly
89 * relative) or 1 (absolute). throw out any leading '/'.
90 */
91 filepath(std::string_view s) : encoded(false) {
92 set_path(s);
93 }
94 filepath(const char *s) : encoded(false) {
95 set_path(std::string_view(s));
96 }
97
98 void set_path(std::string_view s, inodeno_t b) {
99 path = s;
100 ino = b;
101 }
102 void set_path(std::string_view s) {
103 if (s[0] == '/') {
104 path = s.substr(1);
105 ino = 1;
106 } else {
107 ino = 0;
108 path = s;
109 }
110 bits.clear();
111 }
112
113
114 // accessors
115 inodeno_t get_ino() const { return ino; }
116 const string& get_path() const { return path; }
117 const char *c_str() const { return path.c_str(); }
118
119 int length() const { return path.length(); }
120 unsigned depth() const {
121 if (bits.empty() && path.length() > 0) parse_bits();
122 return bits.size();
123 }
124 bool empty() const { return path.length() == 0 && ino == 0; }
125
126 bool absolute() const { return ino == 1; }
127 bool pure_relative() const { return ino == 0; }
128 bool ino_relative() const { return ino > 0; }
129
130 const string& operator[](int i) const {
131 if (bits.empty() && path.length() > 0) parse_bits();
132 return bits[i];
133 }
134
135 const string& last_dentry() const {
136 if (bits.empty() && path.length() > 0) parse_bits();
137 ceph_assert(!bits.empty());
138 return bits[ bits.size()-1 ];
139 }
140
141 filepath prefixpath(int s) const {
142 filepath t(ino);
143 for (int i=0; i<s; i++)
144 t.push_dentry(bits[i]);
145 return t;
146 }
147 filepath postfixpath(int s) const {
148 filepath t;
149 for (unsigned i=s; i<bits.size(); i++)
150 t.push_dentry(bits[i]);
151 return t;
152 }
153
154
155 // modifiers
156 // string can be relative "a/b/c" (ino=0) or absolute "/a/b/c" (ino=1)
157 void _set_ino(inodeno_t i) { ino = i; }
158 void clear() {
159 ino = 0;
160 path = "";
161 bits.clear();
162 }
163
164 void pop_dentry() {
165 if (bits.empty() && path.length() > 0)
166 parse_bits();
167 bits.pop_back();
168 rebuild_path();
169 }
170 void push_dentry(std::string_view s) {
171 if (bits.empty() && path.length() > 0)
172 parse_bits();
173 if (!bits.empty())
174 path += "/";
175 path += s;
176 bits.emplace_back(s);
177 }
178 void push_dentry(const string& s) {
179 push_dentry(std::string_view(s));
180 }
181 void push_dentry(const char *cs) {
182 push_dentry(std::string_view(cs, strlen(cs)));
183 }
184 void push_front_dentry(const string& s) {
185 bits.insert(bits.begin(), s);
186 rebuild_path();
187 }
188 void append(const filepath& a) {
189 ceph_assert(a.pure_relative());
190 for (unsigned i=0; i<a.depth(); i++)
191 push_dentry(a[i]);
192 }
193
194 // encoding
195 void encode(bufferlist& bl) const {
196 using ceph::encode;
197 __u8 struct_v = 1;
(2) Event overrun-buffer-val: |
Overrunning buffer pointed to by "struct_v" of 1 bytes by passing it to a function which accesses it at byte offset 7. [details] |
Also see events: |
[assignment] |
198 encode(struct_v, bl);
199 encode(ino, bl);
200 encode(path, bl);
201 }
202 void decode(bufferlist::const_iterator& blp) {
203 using ceph::decode;
204 bits.clear();
205 __u8 struct_v;
206 decode(struct_v, blp);
207 decode(ino, blp);
208 decode(path, blp);
209 encoded = true;
210 }
211 void dump(Formatter *f) const {
212 f->dump_unsigned("base_ino", ino);
213 f->dump_string("relative_path", path);
214 }
215 static void generate_test_instances(list<filepath*>& o) {
216 o.push_back(new filepath);
217 o.push_back(new filepath("/usr/bin", 0));
218 o.push_back(new filepath("/usr/sbin", 1));
219 o.push_back(new filepath("var/log", 1));
220 o.push_back(new filepath("foo/bar", 101));
221 }
222
223 bool is_last_dot_or_dotdot() const {
224 if (depth() > 0) {
225 std::string dname = last_dentry();
226 if (dname == "." || dname == "..") {
227 return true;
228 }
229 }
230
231 return false;
232 }
233 };
234
235 WRITE_CLASS_ENCODER(filepath)
236
237 inline ostream& operator<<(ostream& out, const filepath& path)
238 {
239 if (path.get_ino()) {
240 out << '#' << path.get_ino();
241 if (path.length())
242 out << '/';
243 }
244 return out << path.get_path();
245 }
246
247 #endif
248