mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add rename(2) and renameat(2).
This commit is contained in:
parent
fd6098a3a2
commit
8e0aefda20
16 changed files with 256 additions and 4 deletions
|
@ -200,6 +200,8 @@ readdirents.o \
|
|||
read.o \
|
||||
removeat.o \
|
||||
remove.o \
|
||||
renameat.o \
|
||||
rename.o \
|
||||
rmdir.o \
|
||||
sbrk.o \
|
||||
scanf.o \
|
||||
|
|
|
@ -301,7 +301,18 @@ struct fsm_req_rmdir
|
|||
//char name[namelen];
|
||||
};
|
||||
|
||||
#define FSM_MSG_NUM 37
|
||||
#define FSM_REQ_RENAME 37
|
||||
struct fsm_req_rename
|
||||
{
|
||||
ino_t olddirino;
|
||||
ino_t newdirino;
|
||||
size_t oldnamelen;
|
||||
size_t newnamelen;
|
||||
//char oldname[oldnamelen];
|
||||
//char newname[newnamelen];
|
||||
};
|
||||
|
||||
#define FSM_MSG_NUM 38
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
|
|
|
@ -104,6 +104,7 @@ extern int putchar(int c);
|
|||
extern int puts(const char* str);
|
||||
extern int removeat(int dirrfd, const char* path);
|
||||
extern int remove(const char* path);
|
||||
extern int renameat(int oldfd, const char* oldname, int newfd, const char* newname);
|
||||
extern int rename(const char* oldname, const char* newname);
|
||||
extern void rewind(FILE* stream);
|
||||
extern int snprintf(char* restrict s, size_t n, const char* restrict format, ...);
|
||||
|
@ -138,7 +139,6 @@ extern int getc_unlocked(FILE* stream);
|
|||
extern int pclose(FILE* steam);
|
||||
extern int putchar_unlocked(int c);
|
||||
extern int putc_unlocked(int c, FILE* steam);
|
||||
extern int renameat(int oldfd, const char* oldname, int newfd, const char* newname);
|
||||
extern int setvbuf(FILE* restrict stream, char* restrict buf, int type, size_t size);
|
||||
extern int vdprintf(int fildes, const char* restrict format, __gnuc_va_list ap);
|
||||
extern void flockfile(FILE* file);
|
||||
|
|
31
libc/rename.cpp
Normal file
31
libc/rename.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The Sortix C Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
rename.cpp
|
||||
Moves a directory entry within the same file system.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" int rename(const char* oldname, const char* newname)
|
||||
{
|
||||
return renameat(AT_FDCWD, oldname, AT_FDCWD, newname);
|
||||
}
|
36
libc/renameat.cpp
Normal file
36
libc/renameat.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The Sortix C Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
renameat.cpp
|
||||
Moves a directory entry within the same file system.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
DEFN_SYSCALL4(int, sys_renameat, SYSCALL_RENAMEAT, int, const char*, int, const char*);
|
||||
|
||||
extern "C" int renameat(int olddir, const char* oldname, int newdir,
|
||||
const char* newname)
|
||||
{
|
||||
return sys_renameat(olddir, oldname, newdir, newname);
|
||||
}
|
|
@ -396,6 +396,28 @@ int Descriptor::symlink(ioctx_t* ctx, const char* oldname, const char* filename)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int Descriptor::rename_here(ioctx_t* ctx, Ref<Descriptor> from,
|
||||
const char* oldpath, const char* newpath)
|
||||
{
|
||||
char* olddir_elem;
|
||||
char* newdir_elem;
|
||||
Ref<Descriptor> olddir = OpenDirContainingPath(ctx, from, oldpath,
|
||||
&olddir_elem);
|
||||
if ( !olddir ) return -1;
|
||||
|
||||
Ref<Descriptor> newdir = OpenDirContainingPath(ctx, Ref<Descriptor>(this),
|
||||
newpath, &newdir_elem);
|
||||
if ( !newdir ) { delete[] olddir_elem; return -1; }
|
||||
|
||||
int ret = newdir->vnode->rename_here(ctx, olddir->vnode, olddir_elem,
|
||||
newdir_elem);
|
||||
|
||||
delete[] newdir_elem;
|
||||
delete[] olddir_elem;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t Descriptor::readlink(ioctx_t* ctx, char* buf, size_t bufsize)
|
||||
{
|
||||
return vnode->readlink(ctx, buf, bufsize);
|
||||
|
|
|
@ -393,5 +393,72 @@ int Dir::symlink(ioctx_t* /*ctx*/, const char* oldname, const char* filename)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int Dir::rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
|
||||
const char* newname)
|
||||
{
|
||||
if ( IsDotOrDotDot(oldname) || IsDotOrDotDot(newname) )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
// TODO: Check whether oldpath is an ancestor of newpath.
|
||||
|
||||
// Avoid deadlocks by locking directories in the right order.
|
||||
Dir* from_dir = (Dir*) from.Get();
|
||||
kthread_mutex_t* mutex_ptr1;
|
||||
kthread_mutex_t* mutex_ptr2;
|
||||
if ( from_dir->ino < this->ino )
|
||||
mutex_ptr1 = &from_dir->dirlock,
|
||||
mutex_ptr2 = &this->dirlock;
|
||||
else if ( from_dir->ino == this->ino )
|
||||
{
|
||||
mutex_ptr1 = &this->dirlock,
|
||||
mutex_ptr2 = NULL;
|
||||
if ( !strcmp(oldname, newname) )
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
mutex_ptr1 = &this->dirlock,
|
||||
mutex_ptr2 = &from_dir->dirlock;
|
||||
ScopedLock lock1(mutex_ptr1);
|
||||
ScopedLock lock2(mutex_ptr2);
|
||||
|
||||
size_t from_index = from_dir->FindChild(oldname);
|
||||
if ( from_index == SIZE_MAX )
|
||||
return errno = ENOENT, -1;
|
||||
|
||||
Ref<Inode> the_inode = from_dir->children[from_index].inode;
|
||||
|
||||
size_t to_index = this->FindChild(newname);
|
||||
if ( to_index != SIZE_MAX )
|
||||
{
|
||||
Ref<Inode> existing = this->children[to_index].inode;
|
||||
|
||||
if ( existing->dev == the_inode->dev &&
|
||||
existing->ino == the_inode->ino )
|
||||
return 0;
|
||||
|
||||
if ( S_ISDIR(existing->type) )
|
||||
{
|
||||
Dir* existing_dir = (Dir*) existing.Get();
|
||||
if ( !S_ISDIR(the_inode->type) )
|
||||
return errno = EISDIR, -1;
|
||||
assert(&existing_dir->dirlock != mutex_ptr1);
|
||||
assert(&existing_dir->dirlock != mutex_ptr2);
|
||||
if ( existing_dir->rmdir_me(ctx) != 0 )
|
||||
return -1;
|
||||
}
|
||||
this->children[to_index].inode = the_inode;
|
||||
}
|
||||
else
|
||||
if ( !this->AddChild(newname, the_inode) )
|
||||
return -1;
|
||||
|
||||
from_dir->RemoveChild(from_index);
|
||||
|
||||
if ( S_ISDIR(the_inode->type) )
|
||||
the_inode->link_raw(ctx, "..", Ref<Inode>(this));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace KRAMFS
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -82,6 +82,8 @@ public:
|
|||
virtual int rmdir_me(ioctx_t* ctx);
|
||||
virtual int symlink(ioctx_t* ctx, const char* oldname,
|
||||
const char* filename);
|
||||
virtual int rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
|
||||
const char* newname);
|
||||
|
||||
private:
|
||||
size_t FindChild(const char* filename);
|
||||
|
|
|
@ -214,6 +214,8 @@ public:
|
|||
virtual int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
|
||||
virtual int poll(ioctx_t* ctx, PollNode* node);
|
||||
virtual int rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
|
||||
const char* newname);
|
||||
|
||||
private:
|
||||
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
|
||||
|
@ -1121,6 +1123,28 @@ int Unode::poll(ioctx_t* /*ctx*/, PollNode* /*node*/)
|
|||
return errno = ENOTSUP, -1;
|
||||
}
|
||||
|
||||
int Unode::rename_here(ioctx_t* /*ctx*/, Ref<Inode> from, const char* oldname,
|
||||
const char* newname)
|
||||
{
|
||||
Channel* channel = server->Connect();
|
||||
if ( !channel )
|
||||
return -1;
|
||||
int ret = -1;
|
||||
struct fsm_req_rename msg;
|
||||
msg.olddirino = this->ino;
|
||||
msg.newdirino = from->ino;
|
||||
msg.oldnamelen = strlen(oldname);
|
||||
msg.newnamelen = strlen(newname);
|
||||
size_t extra = msg.oldnamelen + msg.newnamelen;
|
||||
if ( SendMessage(channel, FSM_REQ_RENAME, &msg, sizeof(msg), extra) &&
|
||||
channel->KernelSend(&kctx, oldname, msg.oldnamelen) &&
|
||||
channel->KernelSend(&kctx, newname, msg.newnamelen) &&
|
||||
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
|
||||
ret = 0;
|
||||
channel->KernelClose();
|
||||
return ret;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialization.
|
||||
//
|
||||
|
|
|
@ -79,6 +79,8 @@ public:
|
|||
int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
int gettermmode(ioctx_t* ctx, unsigned* mode);
|
||||
int poll(ioctx_t* ctx, PollNode* node);
|
||||
int rename_here(ioctx_t* ctx, Ref<Descriptor> from, const char* oldpath,
|
||||
const char* newpath);
|
||||
|
||||
private:
|
||||
Ref<Descriptor> open_elem(ioctx_t* ctx, const char* filename, int flags,
|
||||
|
|
|
@ -89,6 +89,8 @@ public:
|
|||
virtual int settermmode(ioctx_t* ctx, unsigned mode) = 0;
|
||||
virtual int gettermmode(ioctx_t* ctx, unsigned* mode) = 0;
|
||||
virtual int poll(ioctx_t* ctx, PollNode* node) = 0;
|
||||
virtual int rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
|
||||
const char* newname) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -154,6 +156,8 @@ public:
|
|||
virtual int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
|
||||
virtual int poll(ioctx_t* ctx, PollNode* node);
|
||||
virtual int rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
|
||||
const char* newname);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -76,6 +76,8 @@ public:
|
|||
int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
int gettermmode(ioctx_t* ctx, unsigned* mode);
|
||||
int poll(ioctx_t* ctx, PollNode* node);
|
||||
int rename_here(ioctx_t* ctx, Ref<Vnode> from, const char* oldname,
|
||||
const char* newname);
|
||||
|
||||
public /*TODO: private*/:
|
||||
Ref<Inode> inode;
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
#define SYSCALL_LINKAT 70
|
||||
#define SYSCALL_FSM_FSBIND 71
|
||||
#define SYSCALL_PPOLL 72
|
||||
#define SYSCALL_MAX_NUM 73 /* index of highest constant + 1 */
|
||||
#define SYSCALL_RENAMEAT 73
|
||||
#define SYSCALL_MAX_NUM 74 /* index of highest constant + 1 */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -281,4 +281,12 @@ int AbstractInode::poll(ioctx_t* /*ctx*/, PollNode* /*node*/)
|
|||
return errno = ENOTSUP, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::rename_here(ioctx_t* /*ctx*/, Ref<Inode> /*from*/,
|
||||
const char* /*oldname*/, const char* /*newname*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_DIR )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTDIR, -1;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -510,6 +510,36 @@ static int sys_tcgetwinsize(int fd, struct winsize* ws)
|
|||
return desc->tcgetwinsize(&ctx, ws);
|
||||
}
|
||||
|
||||
static int sys_renameat_inner(int olddirfd, const char* oldpath,
|
||||
int newdirfd, const char* newpath)
|
||||
{
|
||||
const char* oldrelpath = oldpath;
|
||||
Ref<Descriptor> olddir(PrepareLookup(&oldrelpath, olddirfd));
|
||||
if ( !olddir )
|
||||
return -1;
|
||||
|
||||
const char* newrelpath = newpath;
|
||||
Ref<Descriptor> newdir(PrepareLookup(&newrelpath, newdirfd));
|
||||
if ( !newdir )
|
||||
return -1;
|
||||
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return newdir->rename_here(&ctx, olddir, oldrelpath, newrelpath);
|
||||
}
|
||||
|
||||
static int sys_renameat(int olddirfd, const char* oldpath,
|
||||
int newdirfd, const char* newpath)
|
||||
{
|
||||
char* oldpathcopy = GetStringFromUser(oldpath);
|
||||
if ( !oldpathcopy ) return -1;
|
||||
char* newpathcopy = GetStringFromUser(newpath);
|
||||
if ( !newpathcopy ) { delete[] oldpathcopy; return -1; }
|
||||
int ret = sys_renameat_inner(olddirfd, oldpathcopy, newdirfd, newpathcopy);
|
||||
delete[] newpathcopy;
|
||||
delete[] oldpathcopy;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_ACCESS, (void*) sys_access);
|
||||
|
@ -517,8 +547,8 @@ void Init()
|
|||
Syscall::Register(SYSCALL_CHMOD, (void*) sys_chmod);
|
||||
Syscall::Register(SYSCALL_CHOWN, (void*) sys_chown);
|
||||
Syscall::Register(SYSCALL_CLOSE, (void*) sys_close);
|
||||
Syscall::Register(SYSCALL_DUP, (void*) sys_dup);
|
||||
Syscall::Register(SYSCALL_DUP2, (void*) sys_dup2);
|
||||
Syscall::Register(SYSCALL_DUP, (void*) sys_dup);
|
||||
Syscall::Register(SYSCALL_FACCESSAT, (void*) sys_faccessat);
|
||||
Syscall::Register(SYSCALL_FCHDIR, (void*) sys_fchdir);
|
||||
Syscall::Register(SYSCALL_FCHMODAT, (void*) sys_fchmodat);
|
||||
|
@ -541,6 +571,7 @@ void Init()
|
|||
Syscall::Register(SYSCALL_PWRITE, (void*) sys_pwrite);
|
||||
Syscall::Register(SYSCALL_READDIRENTS, (void*) sys_readdirents);
|
||||
Syscall::Register(SYSCALL_READ, (void*) sys_read);
|
||||
Syscall::Register(SYSCALL_RENAMEAT, (void*) sys_renameat);
|
||||
Syscall::Register(SYSCALL_RMDIR, (void*) sys_rmdir);
|
||||
Syscall::Register(SYSCALL_SEEK, (void*) sys_seek);
|
||||
Syscall::Register(SYSCALL_SETTERMMODE, (void*) sys_settermmode);
|
||||
|
|
|
@ -186,6 +186,15 @@ int Vnode::symlink(ioctx_t* ctx, const char* oldname, const char* filename)
|
|||
return inode->symlink(ctx, oldname, filename);
|
||||
}
|
||||
|
||||
int Vnode::rename_here(ioctx_t* ctx, Ref<Vnode> from, const char* oldname,
|
||||
const char* newname)
|
||||
{
|
||||
if ( from->dev != dev )
|
||||
return errno = EXDEV, -1;
|
||||
// TODO: Force the same mount point here, like Linux does.
|
||||
return inode->rename_here(ctx, from->inode, oldname, newname);
|
||||
}
|
||||
|
||||
ssize_t Vnode::readlink(ioctx_t* ctx, char* buf, size_t bufsiz)
|
||||
{
|
||||
return inode->readlink(ctx, buf, bufsiz);
|
||||
|
|
Loading…
Reference in a new issue