Added new syscall _kern_normalize_path() to normalize a path.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23929 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -143,6 +143,8 @@ extern dev_t _kern_next_device(int32 *_cookie);
|
|||||||
extern status_t _kern_sync(void);
|
extern status_t _kern_sync(void);
|
||||||
extern status_t _kern_entry_ref_to_path(dev_t device, ino_t inode,
|
extern status_t _kern_entry_ref_to_path(dev_t device, ino_t inode,
|
||||||
const char *leaf, char *userPath, size_t pathLength);
|
const char *leaf, char *userPath, size_t pathLength);
|
||||||
|
extern status_t _kern_normalize_path(const char* userPath,
|
||||||
|
bool traverseLink, char* buffer);
|
||||||
extern int _kern_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms);
|
extern int _kern_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms);
|
||||||
extern int _kern_open(int fd, const char *path, int openMode, int perms);
|
extern int _kern_open(int fd, const char *path, int openMode, int perms);
|
||||||
extern int _kern_open_dir_entry_ref(dev_t device, ino_t inode, const char *name);
|
extern int _kern_open_dir_entry_ref(dev_t device, ino_t inode, const char *name);
|
||||||
|
|||||||
@@ -137,6 +137,8 @@ status_t _user_get_next_fd_info(team_id team, uint32 *cookie, struct fd_info *in
|
|||||||
size_t infoSize);
|
size_t infoSize);
|
||||||
status_t _user_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf,
|
status_t _user_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf,
|
||||||
char *userPath, size_t pathLength);
|
char *userPath, size_t pathLength);
|
||||||
|
status_t _user_normalize_path(const char* userPath, bool traverseLink,
|
||||||
|
char* buffer);
|
||||||
int _user_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms);
|
int _user_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms);
|
||||||
int _user_open(int fd, const char *path, int openMode, int perms);
|
int _user_open(int fd, const char *path, int openMode, int perms);
|
||||||
int _user_open_dir_node_ref(dev_t device, ino_t inode);
|
int _user_open_dir_node_ref(dev_t device, ino_t inode);
|
||||||
|
|||||||
@@ -1908,6 +1908,52 @@ fd_and_path_to_dir_vnode(int fd, char *path, struct vnode **_vnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Retrieves the directory vnode and the leaf name of an entry referred
|
||||||
|
to by a vnode + path pair.
|
||||||
|
|
||||||
|
\a path must be given in either case. \a vnode 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 vnode. If \a path is absolute \a vnode is
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
The caller has the responsibility to call put_vnode() on the returned
|
||||||
|
directory vnode.
|
||||||
|
|
||||||
|
\param vnode The vnode. May be \c NULL.
|
||||||
|
\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
|
||||||
|
vnode_and_path_to_dir_vnode(struct vnode* vnode, char *path,
|
||||||
|
struct vnode **_vnode, char *filename, bool kernel)
|
||||||
|
{
|
||||||
|
if (!path)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (*path == '\0')
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
if (vnode == NULL)
|
||||||
|
return path_to_dir_vnode(path, _vnode, filename, kernel);
|
||||||
|
|
||||||
|
status_t status = get_dir_path_and_leaf(path, filename);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
inc_vnode_ref_count(vnode);
|
||||||
|
// vnode_path_to_vnode() always decrements the ref count
|
||||||
|
|
||||||
|
return vnode_path_to_vnode(vnode, path, true, 0, _vnode, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! 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
|
||||||
@@ -3297,6 +3343,7 @@ err:
|
|||||||
|
|
||||||
\param path The path to be normalized.
|
\param path The path to be normalized.
|
||||||
\param buffer The buffer into which the normalized path will be written.
|
\param buffer The buffer into which the normalized path will be written.
|
||||||
|
May be the same one as \a path.
|
||||||
\param bufferSize The size of \a buffer.
|
\param bufferSize The size of \a buffer.
|
||||||
\param kernel \c true, if the IO context of the kernel shall be used,
|
\param kernel \c true, if the IO context of the kernel shall be used,
|
||||||
otherwise that of the team this thread belongs to. Only relevant,
|
otherwise that of the team this thread belongs to. Only relevant,
|
||||||
@@ -7178,6 +7225,113 @@ _user_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
_user_normalize_path(const char* userPath, bool traverseLink, char* buffer)
|
||||||
|
{
|
||||||
|
if (userPath == NULL || buffer == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(buffer))
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
// copy path from userland
|
||||||
|
KPath pathBuffer(B_PATH_NAME_LENGTH + 1);
|
||||||
|
if (pathBuffer.InitCheck() != B_OK)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
char* path = pathBuffer.LockBuffer();
|
||||||
|
|
||||||
|
if (user_strlcpy(path, userPath, B_PATH_NAME_LENGTH) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
// buffer for the leaf part
|
||||||
|
KPath leafBuffer(B_PATH_NAME_LENGTH + 1);
|
||||||
|
if (leafBuffer.InitCheck() != B_OK)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
char* leaf = leafBuffer.LockBuffer();
|
||||||
|
|
||||||
|
VNodePutter dirPutter;
|
||||||
|
struct vnode* dir = NULL;
|
||||||
|
status_t error;
|
||||||
|
|
||||||
|
for (int i = 0; i < B_MAX_SYMLINKS; i++) {
|
||||||
|
// get dir vnode + leaf name
|
||||||
|
struct vnode* nextDir;
|
||||||
|
error = vnode_and_path_to_dir_vnode(dir, path, &nextDir, leaf, false);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
dir = nextDir;
|
||||||
|
strcpy(path, leaf);
|
||||||
|
dirPutter.SetTo(dir);
|
||||||
|
|
||||||
|
// get file vnode
|
||||||
|
inc_vnode_ref_count(dir);
|
||||||
|
struct vnode* fileVnode;
|
||||||
|
int type;
|
||||||
|
error = vnode_path_to_vnode(dir, path, false, 0, &fileVnode, NULL,
|
||||||
|
&type);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
VNodePutter fileVnodePutter(fileVnode);
|
||||||
|
|
||||||
|
if (!traverseLink || !S_ISLNK(type)) {
|
||||||
|
// we're done -- construct the path
|
||||||
|
bool hasLeaf = true;
|
||||||
|
if (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0) {
|
||||||
|
// special cases "." and ".." -- get the dir, forget the leaf
|
||||||
|
inc_vnode_ref_count(dir);
|
||||||
|
error = vnode_path_to_vnode(dir, leaf, false, 0, &nextDir, NULL,
|
||||||
|
NULL);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
dir = nextDir;
|
||||||
|
dirPutter.SetTo(dir);
|
||||||
|
hasLeaf = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the directory path
|
||||||
|
error = dir_vnode_to_path(dir, path, B_PATH_NAME_LENGTH);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// append the leaf name
|
||||||
|
if (hasLeaf) {
|
||||||
|
// insert a directory separator if this is not the file system
|
||||||
|
// root
|
||||||
|
if ((strcmp(path, "/") != 0
|
||||||
|
&& strlcat(path, "/", pathBuffer.BufferSize())
|
||||||
|
>= pathBuffer.BufferSize())
|
||||||
|
|| strlcat(path, leaf, pathBuffer.BufferSize())
|
||||||
|
>= pathBuffer.BufferSize()) {
|
||||||
|
return B_NAME_TOO_LONG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy back to userland
|
||||||
|
int len = user_strlcpy(buffer, path, B_PATH_NAME_LENGTH);
|
||||||
|
if (len < 0)
|
||||||
|
return len;
|
||||||
|
if (len >= B_PATH_NAME_LENGTH)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read link
|
||||||
|
struct stat st;
|
||||||
|
if (FS_CALL(fileVnode, read_symlink) != NULL) {
|
||||||
|
size_t bufferSize = B_PATH_NAME_LENGTH;
|
||||||
|
error = FS_CALL(fileVnode, read_symlink)(fileVnode->mount->cookie,
|
||||||
|
fileVnode->private_node, path, &bufferSize);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
} else
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_LINK_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_user_open_entry_ref(dev_t device, ino_t inode, const char *userName,
|
_user_open_entry_ref(dev_t device, ino_t inode, const char *userName,
|
||||||
int openMode, int perms)
|
int openMode, int perms)
|
||||||
|
|||||||
Reference in New Issue
Block a user