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;
(1) Event assignment: Assigning: "struct_v" = "1".
Also see events: [overrun-buffer-val]
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