* Reviewed checking of empty paths and fixed some occurrences. Thanks to
mjw for the hint. Fixes bug #1516. * Changed _{kern,user}_create_symlink() to no longer check the supplied link string. BeOS seems to do that, but this is not standard conforming. The previous implementation even used the path processed by check_path(), which would potentially have appended a ".". * Some style cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22451 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+105
-89
@@ -1487,25 +1487,28 @@ resolve_volume_root_to_mount_point(struct vnode *vnode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** \brief Gets the directory path and leaf name for a given path.
|
/*! \brief Gets the directory path and leaf name for a given path.
|
||||||
*
|
|
||||||
* The supplied \a path is transformed to refer to the directory part of
|
|
||||||
* the entry identified by the original path, and into the buffer \a filename
|
|
||||||
* the leaf name of the original entry is written.
|
|
||||||
* Neither the returned path nor the leaf name can be expected to be
|
|
||||||
* canonical.
|
|
||||||
*
|
|
||||||
* \param path The path to be analyzed. Must be able to store at least one
|
|
||||||
* additional character.
|
|
||||||
* \param filename The buffer into which the leaf name will be written.
|
|
||||||
* Must be of size B_FILE_NAME_LENGTH at least.
|
|
||||||
* \return \c B_OK, if everything went fine, \c B_NAME_TOO_LONG, if the leaf
|
|
||||||
* name is longer than \c B_FILE_NAME_LENGTH.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
The supplied \a path is transformed to refer to the directory part of
|
||||||
|
the entry identified by the original path, and into the buffer \a filename
|
||||||
|
the leaf name of the original entry is written.
|
||||||
|
Neither the returned path nor the leaf name can be expected to be
|
||||||
|
canonical.
|
||||||
|
|
||||||
|
\param path The path to be analyzed. Must be able to store at least one
|
||||||
|
additional character.
|
||||||
|
\param filename The buffer into which the leaf name will be written.
|
||||||
|
Must be of size B_FILE_NAME_LENGTH at least.
|
||||||
|
\return \c B_OK, if everything went fine, \c B_NAME_TOO_LONG, if the leaf
|
||||||
|
name is longer than \c B_FILE_NAME_LENGTH, or \c B_ENTRY_NOT_FOUND,
|
||||||
|
if the given path name is empty.
|
||||||
|
*/
|
||||||
static status_t
|
static status_t
|
||||||
get_dir_path_and_leaf(char *path, char *filename)
|
get_dir_path_and_leaf(char *path, char *filename)
|
||||||
{
|
{
|
||||||
|
if (*path == '\0')
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
char *p = strrchr(path, '/');
|
char *p = strrchr(path, '/');
|
||||||
// '/' are not allowed in file names!
|
// '/' are not allowed in file names!
|
||||||
|
|
||||||
@@ -1537,7 +1540,8 @@ get_dir_path_and_leaf(char *path, char *filename)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
entry_ref_to_vnode(dev_t mountID, ino_t directoryID, const char *name, struct vnode **_vnode)
|
entry_ref_to_vnode(dev_t mountID, ino_t directoryID, const char *name,
|
||||||
|
struct vnode **_vnode)
|
||||||
{
|
{
|
||||||
char clonedName[B_FILE_NAME_LENGTH + 1];
|
char clonedName[B_FILE_NAME_LENGTH + 1];
|
||||||
if (strlcpy(clonedName, name, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH)
|
if (strlcpy(clonedName, name, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH)
|
||||||
@@ -1550,18 +1554,18 @@ entry_ref_to_vnode(dev_t mountID, ino_t directoryID, const char *name, struct vn
|
|||||||
if (status < 0)
|
if (status < 0)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
return vnode_path_to_vnode(directory, clonedName, false, 0, _vnode, NULL, NULL);
|
return vnode_path_to_vnode(directory, clonedName, false, 0, _vnode, NULL,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns the vnode for the relative path starting at the specified \a vnode.
|
/*! Returns the vnode for the relative path starting at the specified \a vnode.
|
||||||
* \a path must not be NULL.
|
\a path must not be NULL.
|
||||||
* If it returns successfully, \a path contains the name of the last path
|
If it returns successfully, \a path contains the name of the last path
|
||||||
* component.
|
component.
|
||||||
* Note, this reduces the ref_count of the starting \a vnode, no matter if
|
Note, this reduces the ref_count of the starting \a vnode, no matter if
|
||||||
* it is successful or not!
|
it is successful or not!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
|
vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
|
||||||
int count, struct vnode **_vnode, ino_t *_parentID, int *_type)
|
int count, struct vnode **_vnode, ino_t *_parentID, int *_type)
|
||||||
@@ -1577,6 +1581,11 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*path == '\0') {
|
||||||
|
put_vnode(vnode);
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
struct vnode *nextVnode;
|
struct vnode *nextVnode;
|
||||||
ino_t vnodeID;
|
ino_t vnodeID;
|
||||||
@@ -1683,6 +1692,7 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
|
|||||||
// directory ("vnode" still points to that one).
|
// directory ("vnode" still points to that one).
|
||||||
// Cut off all leading slashes if it's the root directory
|
// Cut off all leading slashes if it's the root directory
|
||||||
path = buffer;
|
path = buffer;
|
||||||
|
bool absoluteSymlink = false;
|
||||||
if (path[0] == '/') {
|
if (path[0] == '/') {
|
||||||
// we don't need the old directory anymore
|
// we don't need the old directory anymore
|
||||||
put_vnode(vnode);
|
put_vnode(vnode);
|
||||||
@@ -1691,13 +1701,21 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
|
|||||||
;
|
;
|
||||||
vnode = sRoot;
|
vnode = sRoot;
|
||||||
inc_vnode_ref_count(vnode);
|
inc_vnode_ref_count(vnode);
|
||||||
}
|
|
||||||
inc_vnode_ref_count(vnode);
|
|
||||||
// balance the next recursion - we will decrement the ref_count
|
|
||||||
// of the vnode, no matter if we succeeded or not
|
|
||||||
|
|
||||||
status = vnode_path_to_vnode(vnode, path, traverseLeafLink, count + 1,
|
absoluteSymlink = true;
|
||||||
&nextVnode, &lastParentID, _type);
|
}
|
||||||
|
|
||||||
|
inc_vnode_ref_count(vnode);
|
||||||
|
// balance the next recursion - we will decrement the
|
||||||
|
// ref_count of the vnode, no matter if we succeeded or not
|
||||||
|
|
||||||
|
if (absoluteSymlink && *path == '\0') {
|
||||||
|
// symlink was just "/"
|
||||||
|
nextVnode = vnode;
|
||||||
|
} else {
|
||||||
|
status = vnode_path_to_vnode(vnode, path, traverseLeafLink,
|
||||||
|
count + 1, &nextVnode, &lastParentID, _type);
|
||||||
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
@@ -1743,6 +1761,9 @@ path_to_vnode(char *path, bool traverseLink, struct vnode **_vnode,
|
|||||||
if (!path)
|
if (!path)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (*path == '\0')
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
// figure out if we need to start at root or at cwd
|
// figure out if we need to start at root or at cwd
|
||||||
if (*path == '/') {
|
if (*path == '/') {
|
||||||
if (sRoot == NULL) {
|
if (sRoot == NULL) {
|
||||||
@@ -1754,6 +1775,12 @@ path_to_vnode(char *path, bool traverseLink, struct vnode **_vnode,
|
|||||||
;
|
;
|
||||||
start = sRoot;
|
start = sRoot;
|
||||||
inc_vnode_ref_count(start);
|
inc_vnode_ref_count(start);
|
||||||
|
|
||||||
|
if (*path == '\0') {
|
||||||
|
*_vnode = start;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
struct io_context *context = get_current_io_context(kernel);
|
struct io_context *context = get_current_io_context(kernel);
|
||||||
|
|
||||||
@@ -1771,11 +1798,10 @@ path_to_vnode(char *path, bool traverseLink, struct vnode **_vnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns the vnode in the next to last segment of the path, and returns
|
/*! Returns the vnode in the next to last segment of the path, and returns
|
||||||
* the last portion in filename.
|
the last portion in filename.
|
||||||
* The path buffer must be able to store at least one additional character.
|
The path buffer must be able to store at least one additional character.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel)
|
path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel)
|
||||||
{
|
{
|
||||||
@@ -1787,37 +1813,38 @@ path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** \brief Retrieves the directory vnode and the leaf name of an entry referred
|
/*! \brief Retrieves the directory vnode and the leaf name of an entry referred
|
||||||
* to by a FD + path pair.
|
to by a FD + path pair.
|
||||||
*
|
|
||||||
* \a path must be given in either case. \a fd might be omitted, in which
|
|
||||||
* case \a path is either an absolute path or one relative to the current
|
|
||||||
* directory. If both a supplied and \a path is relative it is reckoned off
|
|
||||||
* of the directory referred to by \a fd. If \a path is absolute \a fd is
|
|
||||||
* ignored.
|
|
||||||
*
|
|
||||||
* The caller has the responsibility to call put_vnode() on the returned
|
|
||||||
* directory vnode.
|
|
||||||
*
|
|
||||||
* \param fd The FD. May be < 0.
|
|
||||||
* \param path The absolute or relative path. Must not be \c NULL. The buffer
|
|
||||||
* is modified by this function. It must have at least room for a
|
|
||||||
* string one character longer than the path it contains.
|
|
||||||
* \param _vnode A pointer to a variable the directory vnode shall be written
|
|
||||||
* into.
|
|
||||||
* \param filename A buffer of size B_FILE_NAME_LENGTH or larger into which
|
|
||||||
* the leaf name of the specified entry will be written.
|
|
||||||
* \param kernel \c true, if invoked from inside the kernel, \c false if
|
|
||||||
* invoked from userland.
|
|
||||||
* \return \c B_OK, if everything went fine, another error code otherwise.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
\a path must be given in either case. \a fd might be omitted, in which
|
||||||
|
case \a path is either an absolute path or one relative to the current
|
||||||
|
directory. If both a supplied and \a path is relative it is reckoned off
|
||||||
|
of the directory referred to by \a fd. If \a path is absolute \a fd is
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
The caller has the responsibility to call put_vnode() on the returned
|
||||||
|
directory vnode.
|
||||||
|
|
||||||
|
\param fd The FD. May be < 0.
|
||||||
|
\param path The absolute or relative path. Must not be \c NULL. The buffer
|
||||||
|
is modified by this function. It must have at least room for a
|
||||||
|
string one character longer than the path it contains.
|
||||||
|
\param _vnode A pointer to a variable the directory vnode shall be written
|
||||||
|
into.
|
||||||
|
\param filename A buffer of size B_FILE_NAME_LENGTH or larger into which
|
||||||
|
the leaf name of the specified entry will be written.
|
||||||
|
\param kernel \c true, if invoked from inside the kernel, \c false if
|
||||||
|
invoked from userland.
|
||||||
|
\return \c B_OK, if everything went fine, another error code otherwise.
|
||||||
|
*/
|
||||||
static status_t
|
static status_t
|
||||||
fd_and_path_to_dir_vnode(int fd, char *path, struct vnode **_vnode,
|
fd_and_path_to_dir_vnode(int fd, char *path, struct vnode **_vnode,
|
||||||
char *filename, bool kernel)
|
char *filename, bool kernel)
|
||||||
{
|
{
|
||||||
if (!path)
|
if (!path)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
if (*path == '\0')
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return path_to_dir_vnode(path, _vnode, filename, kernel);
|
return path_to_dir_vnode(path, _vnode, filename, kernel);
|
||||||
|
|
||||||
@@ -1829,9 +1856,8 @@ fd_and_path_to_dir_vnode(int fd, char *path, struct vnode **_vnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns a vnode's name in the d_name field of a supplied dirent buffer.
|
/*! Returns a vnode's name in the d_name field of a supplied dirent buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
get_vnode_name(struct vnode *vnode, struct vnode *parent, struct dirent *buffer,
|
get_vnode_name(struct vnode *vnode, struct vnode *parent, struct dirent *buffer,
|
||||||
size_t bufferSize)
|
size_t bufferSize)
|
||||||
@@ -2049,12 +2075,11 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Checks the length of every path component, and adds a '.'
|
/*! Checks the length of every path component, and adds a '.'
|
||||||
* if the path ends in a slash.
|
if the path ends in a slash.
|
||||||
* The given path buffer must be able to store at least one
|
The given path buffer must be able to store at least one
|
||||||
* additional character.
|
additional character.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
check_path(char *to)
|
check_path(char *to)
|
||||||
{
|
{
|
||||||
@@ -2131,13 +2156,12 @@ get_vnode_from_fd(int fd, bool kernel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Gets the vnode from an FD + path combination. If \a fd is lower than zero,
|
/*! Gets the vnode from an FD + path combination. If \a fd is lower than zero,
|
||||||
* only the path will be considered. In this case, the \a path must not be
|
only the path will be considered. In this case, the \a path must not be
|
||||||
* NULL.
|
NULL.
|
||||||
* If \a fd is a valid file descriptor, \a path may be NULL for directories,
|
If \a fd is a valid file descriptor, \a path may be NULL for directories,
|
||||||
* and should be NULL for files.
|
and should be NULL for files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink,
|
fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink,
|
||||||
struct vnode **_vnode, ino_t *_parentID, bool kernel)
|
struct vnode **_vnode, ino_t *_parentID, bool kernel)
|
||||||
@@ -2145,6 +2169,9 @@ fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink,
|
|||||||
if (fd < 0 && !path)
|
if (fd < 0 && !path)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (path != NULL && *path == '\0')
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
if (fd < 0 || (path != NULL && path[0] == '/')) {
|
if (fd < 0 || (path != NULL && path[0] == '/')) {
|
||||||
// no FD or absolute path
|
// no FD or absolute path
|
||||||
return path_to_vnode(path, traverseLeafLink, _vnode, _parentID, kernel);
|
return path_to_vnode(path, traverseLeafLink, _vnode, _parentID, kernel);
|
||||||
@@ -6256,18 +6283,11 @@ status_t
|
|||||||
_kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
|
_kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
|
||||||
{
|
{
|
||||||
KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
|
KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
|
||||||
KPath toPathBuffer(toPath, false, B_PATH_NAME_LENGTH + 1);
|
if (pathBuffer.InitCheck() != B_OK)
|
||||||
if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK)
|
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
char *toBuffer = toPathBuffer.LockBuffer();
|
|
||||||
|
|
||||||
status_t status = check_path(toBuffer);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
return common_create_symlink(fd, pathBuffer.LockBuffer(),
|
return common_create_symlink(fd, pathBuffer.LockBuffer(),
|
||||||
toBuffer, mode, true);
|
toPath, mode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -7097,10 +7117,6 @@ _user_create_symlink(int fd, const char *userPath, const char *userToPath,
|
|||||||
|| user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH) < B_OK)
|
|| user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
status_t status = check_path(toPath);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
return common_create_symlink(fd, path, toPath, mode, false);
|
return common_create_symlink(fd, path, toPath, mode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user