2 * Copyright 2004-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2008-2017, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
8 /*! A simple class wrapping a path. Has a fixed-sized buffer. */
22 //#define TRACE(x) dprintf x
25 KPath::KPath(size_t bufferSize
)
35 SetTo(NULL
, DEFAULT
, bufferSize
);
39 KPath::KPath(const char* path
, int32 flags
, size_t bufferSize
)
49 SetTo(path
, flags
, bufferSize
);
53 KPath::KPath(const KPath
& other
)
74 KPath::SetTo(const char* path
, int32 flags
, size_t bufferSize
)
77 bufferSize
= B_PATH_NAME_LENGTH
;
79 // free the previous buffer, if the buffer size differs
80 if (fBuffer
!= NULL
&& fBufferSize
!= bufferSize
) {
88 fBufferSize
= bufferSize
;
89 fLazy
= (flags
& LAZY_ALLOC
) != 0;
90 fIsNull
= path
== NULL
;
92 if (path
!= NULL
|| !fLazy
) {
93 status_t status
= _AllocateBuffer();
98 return SetPath(path
, flags
);
103 KPath::Adopt(KPath
& other
)
107 fBuffer
= other
.fBuffer
;
108 fBufferSize
= other
.fBufferSize
;
109 fPathLength
= other
.fPathLength
;
111 fFailed
= other
.fFailed
;
112 fIsNull
= other
.fIsNull
;
114 other
.fBuffer
= NULL
;
116 other
.fBufferSize
= 0;
117 other
.fPathLength
= 0;
118 other
.fFailed
= false;
119 other
.fIsNull
= other
.fLazy
;
124 KPath::InitCheck() const
126 if (fBuffer
!= NULL
|| (fLazy
&& !fFailed
&& fBufferSize
!= 0))
129 return fFailed
? B_NO_MEMORY
: B_NO_INIT
;
133 /*! \brief Sets the buffer to \a path.
135 \param flags Understands the following two options:
137 - \c TRAVERSE_LEAF_LINK
140 KPath::SetPath(const char* path
, int32 flags
)
142 if (path
== NULL
&& fLazy
&& fBuffer
== NULL
) {
147 if (fBuffer
== NULL
) {
149 status_t status
= _AllocateBuffer();
159 if ((flags
& NORMALIZE
) != 0) {
161 status_t status
= _Normalize(path
,
162 (flags
& TRAVERSE_LEAF_LINK
) != 0);
166 // don't normalize path
167 size_t length
= strlen(path
);
168 if (length
>= fBufferSize
)
169 return B_BUFFER_OVERFLOW
;
171 memcpy(fBuffer
, path
, length
+ 1);
172 fPathLength
= length
;
173 _ChopTrailingSlashes();
188 return fIsNull
? NULL
: fBuffer
;
192 /*! \brief Locks the buffer for external changes.
194 \param force In lazy mode, this will allocate a buffer when set.
195 Otherwise, \c NULL will be returned if set to NULL.
198 KPath::LockBuffer(bool force
)
200 if (fBuffer
== NULL
&& fLazy
) {
201 if (fIsNull
&& !force
)
207 if (fBuffer
== NULL
|| fLocked
)
218 KPath::UnlockBuffer()
221 TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n"));
230 fPathLength
= strnlen(fBuffer
, fBufferSize
);
231 if (fPathLength
== fBufferSize
) {
232 TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n"));
234 fBuffer
[fPathLength
] = '\0';
236 _ChopTrailingSlashes();
241 KPath::DetachBuffer()
243 char* buffer
= fBuffer
;
245 if (fBuffer
!= NULL
) {
261 for (int32 i
= fPathLength
- 1; i
>= 0; i
--) {
262 if (fBuffer
[i
] == '/')
263 return fBuffer
+ i
+ 1;
271 KPath::ReplaceLeaf(const char* newLeaf
)
273 const char* leaf
= Leaf();
277 int32 leafIndex
= leaf
- fBuffer
;
278 // chop off the current leaf (don't replace "/", though)
279 if (leafIndex
!= 0 || fBuffer
[leafIndex
- 1]) {
280 fBuffer
[leafIndex
] = '\0';
281 fPathLength
= leafIndex
;
282 _ChopTrailingSlashes();
285 // if a leaf was given, append it
287 return Append(newLeaf
);
295 // get the leaf -- bail out, if not initialized or only the "/" is left
296 const char* leaf
= Leaf();
297 if (leaf
== NULL
|| leaf
== fBuffer
|| leaf
[0] == '\0')
301 int32 leafIndex
= leaf
- fBuffer
;
302 fBuffer
[leafIndex
] = '\0';
303 fPathLength
= leafIndex
;
304 _ChopTrailingSlashes();
311 KPath::Append(const char* component
, bool isComponent
)
313 // check initialization and parameter
316 if (component
== NULL
)
318 if (fPathLength
== 0)
319 return SetPath(component
);
321 // get component length
322 size_t componentLength
= strlen(component
);
323 if (componentLength
< 1)
326 // if our current path is empty, we just copy the supplied one
327 // compute the result path len
328 bool insertSlash
= isComponent
&& fBuffer
[fPathLength
- 1] != '/'
329 && component
[0] != '/';
330 size_t resultPathLength
= fPathLength
+ componentLength
331 + (insertSlash
? 1 : 0);
332 if (resultPathLength
>= fBufferSize
)
333 return B_BUFFER_OVERFLOW
;
335 // compose the result path
337 fBuffer
[fPathLength
++] = '/';
338 memcpy(fBuffer
+ fPathLength
, component
, componentLength
+ 1);
339 fPathLength
= resultPathLength
;
345 KPath::Normalize(bool traverseLeafLink
)
349 if (fPathLength
== 0)
352 return _Normalize(fBuffer
, traverseLeafLink
);
357 KPath::operator=(const KPath
& other
)
359 SetTo(other
.fBuffer
, fLazy
? KPath::LAZY_ALLOC
: KPath::DEFAULT
,
366 KPath::operator=(const char* path
)
374 KPath::operator==(const KPath
& other
) const
377 return !other
.fBuffer
;
379 return other
.fBuffer
!= NULL
380 && fPathLength
== other
.fPathLength
381 && strcmp(fBuffer
, other
.fBuffer
) == 0;
386 KPath::operator==(const char* path
) const
391 return path
!= NULL
&& strcmp(fBuffer
, path
) == 0;
396 KPath::operator!=(const KPath
& other
) const
398 return !(*this == other
);
403 KPath::operator!=(const char* path
) const
405 return !(*this == path
);
410 KPath::_AllocateBuffer()
412 if (fBuffer
== NULL
&& fBufferSize
!= 0)
413 fBuffer
= (char*)malloc(fBufferSize
);
414 if (fBuffer
== NULL
) {
426 KPath::_Normalize(const char* path
, bool traverseLeafLink
)
428 status_t error
= vfs_normalize_path(path
, fBuffer
, fBufferSize
,
430 team_get_kernel_team_id() == team_get_current_team_id());
432 // vfs_normalize_path() might have screwed up the previous
433 // path -- unset it completely to avoid weird problems.
439 fPathLength
= strlen(fBuffer
);
445 KPath::_ChopTrailingSlashes()
447 if (fBuffer
!= NULL
) {
448 while (fPathLength
> 1 && fBuffer
[fPathLength
- 1] == '/')
449 fBuffer
[--fPathLength
] = '\0';