xref: /haiku/src/system/kernel/fs/KPath.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 // KPath.cpp
2 
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <KPath.h>
7 #include <team.h>
8 #include <vfs.h>
9 
10 // debugging
11 #define DBG(x)
12 //#define DBG(x) x
13 #define OUT dprintf
14 
15 // constructor
16 KPath::KPath(int32 bufferSize)
17 	: fBuffer(NULL),
18 	  fBufferSize(0),
19 	  fPathLength(0),
20 	  fLocked(false)
21 {
22 	SetTo(NULL, bufferSize);
23 }
24 
25 // constructor
26 KPath::KPath(const char* path, bool normalize, int32 bufferSize)
27 	: fBuffer(NULL),
28 	  fBufferSize(0),
29 	  fPathLength(0),
30 	  fLocked(false)
31 {
32 	SetTo(path, normalize, bufferSize);
33 }
34 
35 // copy constructor
36 KPath::KPath(const KPath& other)
37 	: fBuffer(NULL),
38 	  fBufferSize(0),
39 	  fPathLength(0),
40 	  fLocked(false)
41 {
42 	*this = other;
43 }
44 
45 // destructor
46 KPath::~KPath()
47 {
48 	free(fBuffer);
49 }
50 
51 // SetTo
52 status_t
53 KPath::SetTo(const char* path, bool normalize, int32 bufferSize)
54 {
55 	if (bufferSize <= 0)
56 		bufferSize = B_PATH_NAME_LENGTH;
57 	// free the previous buffer, if the buffer size differs
58 	if (fBuffer && fBufferSize != bufferSize) {
59 		free(fBuffer);
60 		fBuffer = NULL;
61 		fBufferSize = 0;
62 	}
63 	fPathLength = 0;
64 	fLocked = false;
65 	// allocate buffer
66 	if (!fBuffer)
67 		fBuffer = (char*)malloc(bufferSize);
68 	if (!fBuffer)
69 		return B_NO_MEMORY;
70 	if (fBuffer) {
71 		fBufferSize = bufferSize;
72 		fBuffer[0] = '\0';
73 	}
74 	return SetPath(path, normalize);
75 }
76 
77 // InitCheck
78 status_t
79 KPath::InitCheck() const
80 {
81 	return (fBuffer ? B_OK : B_NO_MEMORY);
82 }
83 
84 // SetPath
85 status_t
86 KPath::SetPath(const char *path, bool normalize)
87 {
88 	if (!fBuffer)
89 		return B_NO_INIT;
90 	if (path) {
91 		if (normalize) {
92 			// normalize path
93 			status_t error = vfs_normalize_path(path, fBuffer, fBufferSize,
94 				team_get_kernel_team_id() == team_get_current_team_id());
95 			if (error != B_OK) {
96 				SetPath(NULL);
97 				return error;
98 			}
99 			fPathLength = strlen(fBuffer);
100 		} else {
101 			// don't normalize path
102 			int32 len = strlen(path);
103 			if (len >= fBufferSize)
104 				return B_BUFFER_OVERFLOW;
105 			memcpy(fBuffer, path, len + 1);
106 			fPathLength = len;
107 			_ChopTrailingSlashes();
108 		}
109 	} else {
110 		fBuffer[0] = '\0';
111 		fPathLength = 0;
112 	}
113 	return B_OK;
114 }
115 
116 // Path
117 const char*
118 KPath::Path() const
119 {
120 	return fBuffer;
121 }
122 
123 // Length
124 int32
125 KPath::Length() const
126 {
127 	return fPathLength;
128 }
129 
130 // BufferSize
131 int32
132 KPath::BufferSize() const
133 {
134 	return fBufferSize;
135 }
136 
137 // LockBuffer
138 char *
139 KPath::LockBuffer()
140 {
141 	if (!fBuffer || fLocked)
142 		return NULL;
143 	fLocked = true;
144 	return fBuffer;
145 }
146 
147 // UnlockBuffer
148 void
149 KPath::UnlockBuffer()
150 {
151 	if (!fLocked) {
152 		DBG(OUT("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n"));
153 		return;
154 	}
155 	fLocked = false;
156 	fPathLength = strnlen(fBuffer, fBufferSize);
157 	if (fPathLength == fBufferSize) {
158 		DBG(OUT("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n"));
159 		fPathLength--;
160 		fBuffer[fPathLength] = '\0';
161 	}
162 	_ChopTrailingSlashes();
163 }
164 
165 // Leaf
166 const char *
167 KPath::Leaf() const
168 {
169 	if (!fBuffer)
170 		return NULL;
171 	// only "/" has trailing slashes -- then we have to return the complete
172 	// buffer, as we have to do in case there are no slashes at all
173 	if (fPathLength != 1 || fBuffer[0] != '/') {
174 		for (int32 i = fPathLength - 1; i >= 0; i--) {
175 			if (fBuffer[i] == '/')
176 				return fBuffer + i + 1;
177 		}
178 	}
179 	return fBuffer;
180 }
181 
182 // ReplaceLeaf
183 status_t
184 KPath::ReplaceLeaf(const char *newLeaf)
185 {
186 	const char *leaf = Leaf();
187 	if (!leaf)
188 		return B_NO_INIT;
189 	int32 leafIndex = leaf - fBuffer;
190 	// chop off the current leaf (don't replace "/", though)
191 	if (leafIndex != 0 || fBuffer[leafIndex - 1]) {
192 		fBuffer[leafIndex] = '\0';
193 		fPathLength = leafIndex;
194 		_ChopTrailingSlashes();
195 	}
196 	// if a leaf was given, append it
197 	if (newLeaf)
198 		return Append(newLeaf);
199 	return B_OK;
200 }
201 
202 // Append
203 status_t
204 KPath::Append(const char *component, bool isComponent)
205 {
206 	// check initialization and parameter
207 	if (!fBuffer)
208 		return B_NO_INIT;
209 	if (!component)
210 		return B_BAD_VALUE;
211 	if (fPathLength == 0)
212 		return SetPath(component);
213 	// get component length
214 	int32 componentLen = strlen(component);
215 	if (componentLen < 1)
216 		return B_OK;
217 	// if our current path is empty, we just copy the supplied one
218 	// compute the result path len
219 	bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/'
220 		&& component[0] != '/';
221 	int32 resultPathLen = fPathLength + componentLen + (insertSlash ? 1 : 0);
222 	if (resultPathLen >= fBufferSize)
223 		return B_BUFFER_OVERFLOW;
224 	// compose the result path
225 	if (insertSlash)
226 		fBuffer[fPathLength++] = '/';
227 	memcpy(fBuffer + fPathLength, component, componentLen + 1);
228 	fPathLength = resultPathLen;
229 	return B_OK;
230 }
231 
232 // =
233 KPath&
234 KPath::operator=(const KPath& other)
235 {
236 	SetTo(other.fBuffer, other.fBufferSize);
237 	return *this;
238 }
239 
240 // =
241 KPath&
242 KPath::operator=(const char* path)
243 {
244 	SetTo(path);
245 	return *this;
246 }
247 
248 // ==
249 bool
250 KPath::operator==(const KPath& other) const
251 {
252 	if (!fBuffer)
253 		return (!other.fBuffer);
254 	return (other.fBuffer
255 		&& fPathLength == other.fPathLength
256 		&& strcmp(fBuffer, other.fBuffer) == 0);
257 }
258 
259 // ==
260 bool
261 KPath::operator==(const char* path) const
262 {
263 	if (!fBuffer)
264 		return (!path);
265 	return (path && strcmp(fBuffer, path) == 0);
266 }
267 
268 // !=
269 bool
270 KPath::operator!=(const KPath& other) const
271 {
272 	return !(*this == other);
273 }
274 
275 // !=
276 bool
277 KPath::operator!=(const char* path) const
278 {
279 	return !(*this == path);
280 }
281 
282 // _ChopTrailingSlashes
283 void
284 KPath::_ChopTrailingSlashes()
285 {
286 	if (fBuffer) {
287 		while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/')
288 			fBuffer[--fPathLength] = '\0';
289 	}
290 }
291 
292