1 //----------------------------------------------------------------------
2 // This software is part of the OpenBeOS distribution and is covered
4 //----------------------------------------------------------------------
6 \file storage_support.cpp
7 Implementations of miscellaneous internal Storage Kit support functions.
14 #include <StorageDefs.h>
15 #include <SupportDefs.h>
19 #include "storage_support.h"
26 /*! \param path the path
27 \return \c true, if \a path is not \c NULL and absolute, \c false otherwise
30 is_absolute_path(const char *path
)
32 return (path
&& path
[0] == '/');
36 /*! \brief Parses the supplied path and returns the position of the leaf name
37 part of the path and the length of its directory path part.
39 The value returned in \a fullPath is guaranteed to be > 0, i.e. the
40 function always returns a non-empty directory path part. The leaf name
41 part may be empty though (i.e. \code leafStart == leafEnd \endcode), which
42 will happen, if the supplied path consists only of one component.
44 \param fullPath The path to be parsed.
45 \param dirEnd Reference to a variable into which the end index of the
46 directory part shall be written. The index is exclusive.
47 \param leafStart Reference to a variable into which the start index of
48 the leaf name part shall be written. The index is inclusive.
49 \param leafEnd Reference to a variable into which the end index of
50 the leaf name part shall be written. The index is exclusive.
51 \return \c B_OK, if everything went fine, B_BAD_VALUE, if the supplied
55 parse_path(const char *fullPath
, int &dirEnd
, int &leafStart
, int &leafEnd
)
57 // check path and get length
60 int pathLen
= strlen(fullPath
);
63 // find then end of the leaf name (skip trailing '/')
65 while (i
>= 0 && fullPath
[i
] == '/')
69 // fullPath consists of slashes only
70 dirEnd
= leafStart
= leafEnd
= 1;
73 // find the start of the leaf name
74 while (i
>= 0 && fullPath
[i
] != '/')
78 // fullPath contains only one component
79 dirEnd
= leafStart
= leafEnd
;
82 // find the end of the dir path
83 while (i
>= 0 && fullPath
[i
] == '/')
86 if (dirEnd
== 0) // => fullPath[0] == '/' (an absolute path)
92 /*! \brief Parses the supplied path and returns the leaf name part of the path
93 and its directory path part.
95 The value returned in \a fullPath is guaranteed to be > 0, i.e. the
96 function always returns a non-empty directory path part. The leaf name
97 part may be empty though (i.e. \code leafStart == leafEnd \endcode), which
98 will happen, if the supplied path consists only of one component.
100 \param fullPath The path to be parsed.
101 \param dirPath Pointer to a character array of size \c B_PATH_NAME_LENGTH
102 or greater, into which the directory part shall be written.
104 \param leaf Pointer to a character array of size \c B_FILE_NAME_LENGTH
105 or greater, into which the leaf name part shall be written.
107 \return \c B_OK, if everything went fine, B_BAD_VALUE, if the supplied
111 parse_path(const char *fullPath
, char *dirPath
, char *leaf
)
113 // parse the path and check the lengths
114 int leafStart
, leafEnd
, dirEnd
;
115 status_t error
= parse_path(fullPath
, dirEnd
, leafStart
, leafEnd
);
118 if (dirEnd
>= B_PATH_NAME_LENGTH
119 || leafEnd
- leafStart
>= B_FILE_NAME_LENGTH
) {
120 return B_NAME_TOO_LONG
;
122 // copy the result strings
124 strlcpy(dirPath
, fullPath
, dirEnd
+ 1);
126 strlcpy(leaf
, fullPath
+ leafStart
, leafEnd
- leafStart
+ 1);
130 // internal_parse_path
133 internal_parse_path(const char *fullPath
, int &leafStart
, int &leafEnd
,
136 if (fullPath
== NULL
)
139 enum PathParserState
{ PPS_START
, PPS_LEAF
} state
= PPS_START
;
141 int len
= strlen(fullPath
);
148 for (int pos
= len
-1; ; pos
--) {
154 // Skip all trailing '/' chars, then move on to
155 // reading the leaf name
156 if (fullPath
[pos
] != '/') {
163 // Read leaf name chars until we hit a '/' char
164 if (fullPath
[pos
] == '/') {
177 /*! The caller is responsible for deleting the returned directory path name
179 \param fullPath the path name to be split
180 \param path a variable the directory path name pointer shall
181 be written into, may be NULL
182 \param leaf a variable the leaf name pointer shall be
183 written into, may be NULL
186 split_path(const char *fullPath
, char *&path
, char *&leaf
)
188 return split_path(fullPath
, &path
, &leaf
);
191 /*! The caller is responsible for deleting the returned directory path name
193 \param fullPath the path name to be split
194 \param path a pointer to a variable the directory path name pointer shall
195 be written into, may be NULL
196 \param leaf a pointer to a variable the leaf name pointer shall be
197 written into, may be NULL
200 split_path(const char *fullPath
, char **path
, char **leaf
)
207 if (fullPath
== NULL
)
210 int leafStart
, leafEnd
, pathEnd
, len
;
211 internal_parse_path(fullPath
, leafStart
, leafEnd
, pathEnd
);
214 // Tidy up/handle special cases
217 // Handle special cases
218 if (fullPath
[0] == '/') {
231 } else if (fullPath
[0] == 0) {
232 // Handle "", which we'll treat as "./"
245 } else if (leafStart
== -1) {
246 // fullPath is just an entry name, no parent directories specified
248 } else if (pathEnd
== -1) {
249 // The path is '/' (since pathEnd would be -2 if we had
250 // run out of characters before hitting a '/')
254 // Alloc new strings and copy the path and leaf over
264 *path
= new char[len
+1];
265 memcpy(*path
, fullPath
, len
);
270 len
= leafEnd
- leafStart
+ 1;
271 *leaf
= new char[len
+1];
272 memcpy(*leaf
, fullPath
+ leafStart
, len
);
275 } catch (std::bad_alloc exception
) {
285 /*! The length of the first component is returned as well as the index at
286 which the next one starts. These values are only valid, if the function
288 \param path the path to be parsed
289 \param length the variable the length of the first component is written
291 \param nextComponent the variable the index of the next component is
292 written into. \c 0 is returned, if there is no next component.
293 \return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise
296 parse_first_path_component(const char *path
, int32
& length
,
297 int32
& nextComponent
)
299 status_t error
= (path
? B_OK
: B_BAD_VALUE
);
302 // find first '/' or end of name
303 for (; path
[i
] != '/' && path
[i
] != '\0'; i
++);
304 // handle special case "/..." (absolute path)
305 if (i
== 0 && path
[i
] != '\0')
308 // find last '/' or end of name
309 for (; path
[i
] == '/' && path
[i
] != '\0'; i
++);
310 if (path
[i
] == '\0') // this covers "" as well
318 /*! A string containing the first component is returned and the index, at
319 which the next one starts. These values are only valid, if the function
321 \param path the path to be parsed
322 \param component the variable the pointer to the newly allocated string
323 containing the first path component is written into. The caller
324 is responsible for delete[]'ing the string.
325 \param nextComponent the variable the index of the next component is
326 written into. \c 0 is returned, if there is no next component.
327 \return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise
330 parse_first_path_component(const char *path
, char *&component
,
331 int32
& nextComponent
)
334 status_t error
= parse_first_path_component(path
, length
, nextComponent
);
336 component
= new(nothrow
) char[length
+ 1];
338 strncpy(component
, path
, length
);
339 component
[length
] = '\0';
346 /*! An entry name is considered valid, if its length doesn't exceed
347 \c B_FILE_NAME_LENGTH (including the terminating null) and it doesn't
349 \param entry the entry name
351 - \c B_OK, if \a entry is valid,
352 - \c B_BAD_VALUE, if \a entry is \c NULL or contains a "/",
353 - \c B_NAME_TOO_LONG, if \a entry is too long
354 \note \c "" is considered a valid entry name.
357 check_entry_name(const char *entry
)
359 status_t error
= (entry
? B_OK
: B_BAD_VALUE
);
361 if (strlen(entry
) >= B_FILE_NAME_LENGTH
)
362 error
= B_NAME_TOO_LONG
;
365 for (int32 i
= 0; error
== B_OK
&& entry
[i
] != '\0'; i
++) {
373 /*! An path name is considered valid, if its length doesn't exceed
374 \c B_PATH_NAME_LENGTH (including the terminating null) and each of
375 its components is a valid entry name.
376 \param entry the entry name
378 - \c B_OK, if \a path is valid,
379 - \c B_BAD_VALUE, if \a path is \c NULL,
380 - \c B_NAME_TOO_LONG, if \a path, or any of its components is too long
381 \note \c "" is considered a valid path name.
384 check_path_name(const char *path
)
386 status_t error
= (path
? B_OK
: B_BAD_VALUE
);
387 // check the path components
388 const char *remainder
= path
;
389 int32 length
, nextComponent
;
391 error
= parse_first_path_component(remainder
, length
, nextComponent
);
393 if (length
>= B_FILE_NAME_LENGTH
)
394 error
= B_NAME_TOO_LONG
;
395 remainder
+= nextComponent
;
397 } while (error
== B_OK
&& nextComponent
!= 0);
398 // check the length of the path
399 if (error
== B_OK
&& strlen(path
) >= B_PATH_NAME_LENGTH
)
400 error
= B_NAME_TOO_LONG
;
405 to_lower(const char *str
)
408 to_lower(str
, result
);
413 to_lower(const char *str
, std::string
&result
)
417 for (int i
= 0; i
< (int)strlen(str
); i
++)
418 result
+= tolower(str
[i
]);
424 to_lower(const char *str
, char *result
)
428 for (i
= 0; i
< (int)strlen(str
); i
++)
429 result
[i
] = tolower(str
[i
]);
440 void escape_path(const char *str
, char *result
)
443 int32 len
= strlen(str
);
445 for (int32 i
= 0; i
< len
; i
++) {
467 *(result
++) = escapeChar
;
477 void escape_path(char *str
)
480 char *copy
= new(nothrow
) char[strlen(str
)+1];
483 escape_path(copy
, str
);
489 // device_is_root_device
491 device_is_root_device(dev_t device
)
505 }; // namespace Storage
506 }; // namespace BPrivate