mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add symbolic links.
This commit is contained in:
parent
f26b2d6201
commit
bb3f591057
11 changed files with 262 additions and 69 deletions
2
Makefile
2
Makefile
|
@ -113,7 +113,7 @@ sysroot-source: sysroot-fsh
|
|||
cp Makefile -t "$(SYSROOT)/src"
|
||||
cp README -t "$(SYSROOT)/src"
|
||||
cp -RT build-aux "$(SYSROOT)/src/build-aux"
|
||||
(for D in $(MODULES); do (cp -LR $$D -t "$(SYSROOT)/src" && $(MAKE) -C "$(SYSROOT)/src/$$D" clean) || exit $$?; done)
|
||||
(for D in $(MODULES); do (cp -R $$D -t "$(SYSROOT)/src" && $(MAKE) -C "$(SYSROOT)/src/$$D" clean) || exit $$?; done)
|
||||
|
||||
.PHONY: sysroot-ports
|
||||
sysroot-ports: sysroot-fsh sysroot-base-headers sysroot-system sysroot-source
|
||||
|
|
|
@ -202,6 +202,14 @@ bool RespondRead(int svr, int chl, const uint8_t* buf, size_t count)
|
|||
RespondData(svr, chl, buf, count);
|
||||
}
|
||||
|
||||
bool RespondReadlink(int svr, int chl, const uint8_t* buf, size_t count)
|
||||
{
|
||||
struct fsm_resp_readlink body;
|
||||
body.targetlen = count;
|
||||
return RespondMessage(svr, chl, FSM_RESP_READLINK, &body, sizeof(body)) &&
|
||||
RespondData(svr, chl, buf, count);
|
||||
}
|
||||
|
||||
bool RespondWrite(int svr, int chl, size_t count)
|
||||
{
|
||||
struct fsm_resp_write body;
|
||||
|
@ -577,6 +585,59 @@ void HandleLink(int svr, int chl, struct fsm_req_link* msg, Filesystem* fs)
|
|||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleSymlink(int svr, int chl, struct fsm_req_symlink* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->dirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
|
||||
char* dest_raw = (char*) &(msg[1]);
|
||||
char* dest = (char*) malloc(msg->targetlen + 1);
|
||||
if ( !dest )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
memcpy(dest, dest_raw, msg->namelen);
|
||||
dest[msg->targetlen] = '\0';
|
||||
|
||||
char* path_raw = (char*) dest_raw + msg->targetlen;
|
||||
char* path = (char*) malloc(msg->namelen + 1);
|
||||
if ( !path )
|
||||
{
|
||||
RespondError(svr, chl, errno);
|
||||
inode->Unref();
|
||||
return;
|
||||
}
|
||||
memcpy(path, path_raw, msg->namelen);
|
||||
path[msg->namelen] = '\0';
|
||||
|
||||
if ( inode->Symlink(path, dest) )
|
||||
RespondSuccess(svr, chl);
|
||||
else
|
||||
RespondError(svr, chl, errno);
|
||||
|
||||
free(path);
|
||||
free(dest);
|
||||
inode->Unref();
|
||||
}
|
||||
|
||||
void HandleReadlink(int svr, int chl, struct fsm_req_readlink* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->ino ) { RespondError(svr, chl, EBADF); return; }
|
||||
Inode* inode = fs->GetInode((uint32_t) msg->ino);
|
||||
if ( !inode ) { RespondError(svr, chl, errno); return; }
|
||||
if ( !EXT2_S_ISLNK(inode->Mode()) ) { RespondError(svr, chl, EINVAL); return; }
|
||||
size_t count = inode->Size();
|
||||
uint8_t* buf = (uint8_t*) malloc(count);
|
||||
if ( !buf ) { inode->Unref(); RespondError(svr, chl, errno); return; }
|
||||
ssize_t amount = inode->ReadAt(buf, count, 0);
|
||||
RespondReadlink(svr, chl, buf, amount);
|
||||
inode->Unref();
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void HandleRename(int svr, int chl, struct fsm_req_rename* msg, Filesystem* fs)
|
||||
{
|
||||
if ( fs->num_inodes <= msg->olddirino ) { RespondError(svr, chl, EBADF); return; }
|
||||
|
@ -629,6 +690,8 @@ void HandleIncomingMessage(int svr, int chl, struct fsm_msg_header* hdr,
|
|||
handlers[FSM_REQ_RMDIR] = (handler_t) HandleRemoveDir;
|
||||
handlers[FSM_REQ_UNLINK] = (handler_t) HandleUnlink;
|
||||
handlers[FSM_REQ_LINK] = (handler_t) HandleLink;
|
||||
handlers[FSM_REQ_SYMLINK] = (handler_t) HandleSymlink;
|
||||
handlers[FSM_REQ_READLINK] = (handler_t) HandleReadlink;
|
||||
handlers[FSM_REQ_RENAME] = (handler_t) HandleRename;
|
||||
// TODO: symlink
|
||||
// TODO: readlink
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
@ -289,6 +290,12 @@ bool Inode::FreeIndirect(uint64_t from, uint64_t offset, uint32_t block_id,
|
|||
|
||||
void Inode::Truncate(uint64_t new_size)
|
||||
{
|
||||
if ( 0 < Size() && Size() <= 60 && !data->i_blocks )
|
||||
{
|
||||
fprintf(stderr, "extfs: Truncating optimized symlinks is not implemented!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Enforce a filesize limit!
|
||||
uint64_t old_size = Size();
|
||||
SetSize(new_size);
|
||||
|
@ -638,7 +645,7 @@ Inode* Inode::Unlink(const char* elem, bool directories, bool force)
|
|||
|
||||
ssize_t Inode::ReadAt(uint8_t* buf, size_t s_count, off_t o_offset)
|
||||
{
|
||||
if ( !EXT2_S_ISREG(Mode()) )
|
||||
if ( !EXT2_S_ISREG(Mode()) && !EXT2_S_ISLNK(Mode()) )
|
||||
return errno = EISDIR, -1;
|
||||
if ( o_offset < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
|
@ -652,6 +659,15 @@ ssize_t Inode::ReadAt(uint8_t* buf, size_t s_count, off_t o_offset)
|
|||
return 0;
|
||||
if ( file_size - offset < count )
|
||||
count = file_size - offset;
|
||||
// TODO: This case also needs to be handled in SetSize, Truncate, WriteAt,
|
||||
// and so on.
|
||||
if ( 0 < file_size && file_size <= 60 && !data->i_blocks )
|
||||
{
|
||||
assert(count <= 60);
|
||||
unsigned char* block_data = (unsigned char*) &(data->i_block[0]);
|
||||
memcpy(buf, block_data + offset, count);
|
||||
return (ssize_t) count;
|
||||
}
|
||||
while ( sofar < count )
|
||||
{
|
||||
uint64_t block_id = offset / filesystem->block_size;
|
||||
|
@ -671,7 +687,7 @@ ssize_t Inode::ReadAt(uint8_t* buf, size_t s_count, off_t o_offset)
|
|||
|
||||
ssize_t Inode::WriteAt(const uint8_t* buf, size_t s_count, off_t o_offset)
|
||||
{
|
||||
if ( !EXT2_S_ISREG(Mode()) )
|
||||
if ( !EXT2_S_ISREG(Mode()) && !EXT2_S_ISLNK(Mode()) )
|
||||
return errno = EISDIR, -1;
|
||||
if ( o_offset < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
|
@ -684,6 +700,11 @@ ssize_t Inode::WriteAt(const uint8_t* buf, size_t s_count, off_t o_offset)
|
|||
uint64_t end_at = offset + count;
|
||||
if ( offset < end_at )
|
||||
/* TODO: Overflow! off_t overflow? */{};
|
||||
if ( 0 < file_size && file_size <= 60 && !data->i_blocks )
|
||||
{
|
||||
fprintf(stderr, "extfs: Writing to optimized symlinks is not implemented!\n");
|
||||
return errno = EROFS, -1;
|
||||
}
|
||||
if ( file_size < end_at )
|
||||
Truncate(end_at);
|
||||
while ( sofar < count )
|
||||
|
@ -744,6 +765,44 @@ bool Inode::Rename(Inode* olddir, const char* oldname, const char* newname)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Inode::Symlink(const char* elem, const char* dest)
|
||||
{
|
||||
// TODO: Preferred block group!
|
||||
uint32_t result_inode_id = filesystem->AllocateInode();
|
||||
if ( !result_inode_id )
|
||||
return NULL;
|
||||
|
||||
Inode* result = filesystem->GetInode(result_inode_id);
|
||||
memset(result->data, 0, sizeof(*result->data));
|
||||
result->SetMode((0777 & S_SETABLE) | EXT2_S_IFLNK);
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
result->data->i_atime = now.tv_sec;
|
||||
result->data->i_ctime = now.tv_sec;
|
||||
result->data->i_mtime = now.tv_sec;
|
||||
// TODO: Set all the other inode properties!
|
||||
|
||||
if ( result->WriteAt((const uint8_t*) dest, strlen(dest), 0) < 0 )
|
||||
{
|
||||
error:
|
||||
memset(result->data, 0, sizeof(*result->data));
|
||||
// TODO: dtime
|
||||
result->Unref();
|
||||
filesystem->FreeInode(result_inode_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !Link(elem, result, false) )
|
||||
{
|
||||
result->Truncate(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
result->Unref();
|
||||
return true;
|
||||
}
|
||||
|
||||
Inode* Inode::CreateDirectory(const char* path, mode_t mode)
|
||||
{
|
||||
// TODO: Preferred block group!
|
||||
|
@ -753,7 +812,7 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode)
|
|||
|
||||
Inode* result = filesystem->GetInode(result_inode_id);
|
||||
memset(result->data, 0, sizeof(*result->data));
|
||||
result->SetMode((mode & S_SETABLE) | S_IFDIR);
|
||||
result->SetMode((mode & S_SETABLE) | EXT2_S_IFDIR);
|
||||
|
||||
// Increase the directory count statistics.
|
||||
uint32_t group_id = (result->inode_id - 1) / filesystem->sb->s_inodes_per_group;
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
Block* GetBlockFromTable(Block* table, uint32_t index);
|
||||
Inode* Open(const char* elem, int flags, mode_t mode);
|
||||
bool Link(const char* elem, Inode* dest, bool directories);
|
||||
bool Symlink(const char* elem, const char* dest);
|
||||
Inode* Unlink(const char* elem, bool directories, bool force=false);
|
||||
ssize_t ReadAt(uint8_t* buffer, size_t count, off_t offset);
|
||||
ssize_t WriteAt(const uint8_t* buffer, size_t count, off_t offset);
|
||||
|
|
|
@ -385,6 +385,11 @@ Ref<Descriptor> Descriptor::open(ioctx_t* ctx, const char* filename, int flags,
|
|||
if ( !IsSaneFlagModeCombination(flags, mode) )
|
||||
return errno = EINVAL, Ref<Descriptor>();
|
||||
|
||||
char* filename_mine = NULL;
|
||||
|
||||
size_t symlink_iteration = 0;
|
||||
const size_t MAX_SYMLINK_ITERATION = 20;
|
||||
|
||||
Ref<Descriptor> desc(this);
|
||||
while ( filename[0] )
|
||||
{
|
||||
|
@ -393,7 +398,7 @@ Ref<Descriptor> Descriptor::open(ioctx_t* ctx, const char* filename, int flags,
|
|||
if ( filename[0] == '/' )
|
||||
{
|
||||
if ( !S_ISDIR(desc->type) )
|
||||
return errno = ENOTDIR, Ref<Descriptor>();
|
||||
return delete[] filename_mine, errno = ENOTDIR, Ref<Descriptor>();
|
||||
filename++;
|
||||
continue;
|
||||
}
|
||||
|
@ -402,7 +407,7 @@ Ref<Descriptor> Descriptor::open(ioctx_t* ctx, const char* filename, int flags,
|
|||
size_t slashpos = strcspn(filename, "/");
|
||||
char* elem = String::Substring(filename, 0, slashpos);
|
||||
if ( !elem )
|
||||
return Ref<Descriptor>();
|
||||
return delete[] filename_mine, Ref<Descriptor>();
|
||||
|
||||
// Decide how to open the next element in the path.
|
||||
bool lastelem = IsLastPathElement(filename);
|
||||
|
@ -414,12 +419,69 @@ Ref<Descriptor> Descriptor::open(ioctx_t* ctx, const char* filename, int flags,
|
|||
delete[] elem;
|
||||
|
||||
if ( !next )
|
||||
return Ref<Descriptor>();
|
||||
return delete[] filename_mine, Ref<Descriptor>();
|
||||
|
||||
filename += slashpos;
|
||||
|
||||
bool want_the_symlink_itself = lastelem && (flags & O_SYMLINK_NOFOLLOW);
|
||||
if ( S_ISLNK(next->type) && !want_the_symlink_itself )
|
||||
{
|
||||
if ( (flags & O_NOFOLLOW) && lastelem )
|
||||
return delete[] filename_mine, errno = ELOOP, Ref<Descriptor>();
|
||||
|
||||
if ( symlink_iteration++ == MAX_SYMLINK_ITERATION )
|
||||
return delete[] filename_mine, errno = ELOOP, Ref<Descriptor>();
|
||||
|
||||
ioctx_t kctx;
|
||||
SetupKernelIOCtx(&kctx);
|
||||
|
||||
struct stat st;
|
||||
if ( next->stat(&kctx, &st) < 0 )
|
||||
return delete[] filename_mine, Ref<Descriptor>();
|
||||
assert(0 <= st.st_size);
|
||||
|
||||
if ( (uintmax_t) SIZE_MAX <= (uintmax_t) st.st_size )
|
||||
return delete[] filename_mine, Ref<Descriptor>();
|
||||
|
||||
size_t linkpath_length = (size_t) st.st_size;
|
||||
char* linkpath = new char[linkpath_length + 1];
|
||||
if ( !linkpath )
|
||||
return delete[] filename_mine, Ref<Descriptor>();
|
||||
|
||||
ssize_t linkpath_ret = next->readlink(&kctx, linkpath, linkpath_length);
|
||||
if ( linkpath_ret < 0 )
|
||||
return delete[] linkpath, delete[] filename_mine, Ref<Descriptor>();
|
||||
linkpath[linkpath_length] = '\0';
|
||||
|
||||
linkpath_length = strlen(linkpath);
|
||||
if ( linkpath_length == 0 )
|
||||
return delete[] linkpath, delete[] filename_mine,
|
||||
errno = ENOENT, Ref<Descriptor>();
|
||||
bool link_from_root = linkpath[0] == '/';
|
||||
|
||||
// Either filename is the empty string or starts with a slash.
|
||||
size_t filename_length = strlen(filename);
|
||||
// TODO: Avoid overflow here.
|
||||
size_t new_filename_length = linkpath_length + filename_length;
|
||||
char* new_filename = new char[new_filename_length + 1];
|
||||
if ( !new_filename )
|
||||
return delete[] linkpath, delete[] filename_mine,
|
||||
errno = ENOENT, Ref<Descriptor>();
|
||||
stpcpy(stpcpy(new_filename, linkpath), filename);
|
||||
delete[] filename_mine;
|
||||
filename = filename_mine = new_filename;
|
||||
|
||||
if ( link_from_root )
|
||||
desc = CurrentProcess()->GetRoot();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
desc = next;
|
||||
filename += slashpos;
|
||||
}
|
||||
|
||||
delete[] filename_mine;
|
||||
|
||||
// Abort the open if the user wanted a directory but this wasn't.
|
||||
if ( flags & O_DIRECTORY && !S_ISDIR(desc->type) )
|
||||
return errno = ENOTDIR, Ref<Descriptor>();
|
||||
|
|
|
@ -51,14 +51,15 @@
|
|||
namespace Sortix {
|
||||
namespace KRAMFS {
|
||||
|
||||
File::File(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode)
|
||||
File::File(InodeType inode_type, mode_t type, dev_t dev, ino_t ino, uid_t owner,
|
||||
gid_t group, mode_t mode)
|
||||
{
|
||||
inode_type = INODE_TYPE_FILE;
|
||||
this->inode_type = inode_type;
|
||||
if ( !dev )
|
||||
dev = (dev_t) this;
|
||||
if ( !ino )
|
||||
ino = (ino_t) this;
|
||||
this->type = S_IFREG;
|
||||
this->type = type;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
|
@ -106,6 +107,15 @@ ssize_t File::pwrite(ioctx_t* ctx, const uint8_t* src, size_t count, off_t off)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ssize_t File::readlink(ioctx_t* ctx, char* buf, size_t bufsize)
|
||||
{
|
||||
if ( !S_ISLNK(type) )
|
||||
return errno = EINVAL, -1;
|
||||
if ( (size_t) SSIZE_MAX < bufsize )
|
||||
bufsize = SSIZE_MAX;
|
||||
return fcache.pread(ctx, (uint8_t*) buf, bufsize, 0);
|
||||
}
|
||||
|
||||
Dir::Dir(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode)
|
||||
{
|
||||
inode_type = INODE_TYPE_DIR;
|
||||
|
@ -234,7 +244,8 @@ Ref<Inode> Dir::open(ioctx_t* ctx, const char* filename, int flags, mode_t mode)
|
|||
}
|
||||
if ( !(flags & O_CREATE) )
|
||||
return errno = ENOENT, Ref<Inode>(NULL);
|
||||
Ref<File> file(new File(dev, 0, ctx->uid, ctx->gid, mode));
|
||||
Ref<File> file(new File(INODE_TYPE_FILE, S_IFREG, dev, 0, ctx->uid,
|
||||
ctx->gid, mode));
|
||||
if ( !file )
|
||||
return Ref<Inode>(NULL);
|
||||
if ( !AddChild(filename, file) )
|
||||
|
@ -373,15 +384,36 @@ int Dir::unlink_raw(ioctx_t* /*ctx*/, const char* filename)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Dir::symlink(ioctx_t* /*ctx*/, const char* oldname, const char* filename)
|
||||
int Dir::symlink(ioctx_t* ctx, const char* oldname, const char* filename)
|
||||
{
|
||||
ScopedLock lock(&dir_lock);
|
||||
if ( shut_down )
|
||||
return errno = ENOENT, -1;
|
||||
(void) oldname;
|
||||
(void) filename;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
if ( FindChild(filename) != SIZE_MAX )
|
||||
return errno = EEXIST, -1;
|
||||
Ref<File> file(new File(INODE_TYPE_SYMLINK, S_IFLNK, dev, 0, ctx->uid,
|
||||
ctx->gid, 0777));
|
||||
if ( !file )
|
||||
return Ref<Inode>(NULL);
|
||||
ioctx_t kctx;
|
||||
SetupKernelIOCtx(&kctx);
|
||||
size_t oldname_length = strlen(oldname);
|
||||
size_t so_far = 0;
|
||||
while ( so_far < oldname_length )
|
||||
{
|
||||
#if OFF_MAX < SIZE_MAX
|
||||
if ( (uintmax_t) OFF_MAX < (uintmax_t) so_far )
|
||||
return Ref<Inode>(NULL);
|
||||
#endif
|
||||
ssize_t amount = file->pwrite(&kctx, (const uint8_t*) oldname + so_far,
|
||||
oldname_length - so_far, (off_t) so_far);
|
||||
if ( amount <= 0 )
|
||||
return Ref<Inode>(NULL);
|
||||
so_far += (size_t) amount;
|
||||
}
|
||||
if ( !AddChild(filename, file) )
|
||||
return Ref<Inode>(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dir::rename_here(ioctx_t* ctx, Ref<Inode> from, const char* oldname,
|
||||
|
|
|
@ -41,7 +41,8 @@ struct DirEntry
|
|||
class File : public AbstractInode
|
||||
{
|
||||
public:
|
||||
File(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode);
|
||||
File(InodeType inode_type, mode_t type, dev_t dev, ino_t ino, uid_t owner,
|
||||
gid_t group, mode_t mode);
|
||||
virtual ~File();
|
||||
virtual int truncate(ioctx_t* ctx, off_t length);
|
||||
virtual off_t lseek(ioctx_t* ctx, off_t offset, int whence);
|
||||
|
@ -49,6 +50,7 @@ public:
|
|||
off_t off);
|
||||
virtual ssize_t pwrite(ioctx_t* ctx, const uint8_t* buf, size_t count,
|
||||
off_t off);
|
||||
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
|
||||
private:
|
||||
FileCache fcache;
|
||||
|
|
|
@ -122,6 +122,7 @@ enum InodeType
|
|||
INODE_TYPE_STREAM,
|
||||
INODE_TYPE_TTY,
|
||||
INODE_TYPE_DIR,
|
||||
INODE_TYPE_SYMLINK,
|
||||
};
|
||||
|
||||
class AbstractInode : public Inode
|
||||
|
|
|
@ -260,38 +260,22 @@ static bool ExtractDir(struct initrd_context* ctx, initrd_inode_t* inode, Ref<De
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < numfiles; i++ )
|
||||
{
|
||||
const char* name = initrd_directory_get_filename(ctx, inode, i);
|
||||
if ( !name )
|
||||
return false;
|
||||
if ( IsDotOrDotDot(name) )
|
||||
continue;
|
||||
uint32_t childino = initrd_directory_open(ctx, inode, name);
|
||||
if ( !childino )
|
||||
return false;
|
||||
initrd_inode_t* child = (initrd_inode_t*) initrd_get_inode(ctx, childino);
|
||||
if ( INITRD_S_ISLNK(child->mode) )
|
||||
{
|
||||
size_t filesize;
|
||||
uint8_t* data = initrd_inode_get_data(ctx, child, &filesize);
|
||||
if ( !data )
|
||||
return false;
|
||||
char* dest_path = new char[filesize + 1];
|
||||
if ( !dest_path )
|
||||
char* oldname = new char[filesize + 1];
|
||||
memcpy(oldname, data, filesize);
|
||||
oldname[filesize] = '\0';
|
||||
int ret = dir->symlink(&ctx->ioctx, oldname, name);
|
||||
delete[] oldname;
|
||||
if ( ret < 0 )
|
||||
return false;
|
||||
memcpy(dest_path, data, filesize);
|
||||
dest_path[filesize] = '\0';
|
||||
// TODO: Currently only symbolic links to files inside the same
|
||||
// directory are supported when converted to hardlinks.
|
||||
if ( !strchr(dest_path, '/') )
|
||||
{
|
||||
if ( Ref<Descriptor> dest = dir->open(&ctx->ioctx, dest_path, O_READ, 0) )
|
||||
dir->link(&ctx->ioctx, name, dest);
|
||||
}
|
||||
delete[] dest_path;
|
||||
Ref<Descriptor> desc = dir->open(&ctx->ioctx, name, O_READ | O_SYMLINK_NOFOLLOW, 0);
|
||||
if ( desc )
|
||||
ExtractNode(ctx, child, desc);
|
||||
ctx->amount_extracted += child->size;
|
||||
initrd_progress(ctx);
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ static int sys_openat(int dirfd, const char* path, int flags, mode_t mode)
|
|||
// TODO: This is a hack! Stat the file in some manner and check permissions.
|
||||
static int sys_faccessat(int dirfd, const char* path, int /*mode*/, int flags)
|
||||
{
|
||||
if ( flags & (AT_SYMLINK_NOFOLLOW) )
|
||||
if ( flags & ~(AT_SYMLINK_NOFOLLOW) )
|
||||
return errno = EINVAL, -1;
|
||||
char* pathcopy = GetStringFromUser(path);
|
||||
if ( !pathcopy )
|
||||
|
@ -567,32 +567,26 @@ static int sys_symlinkat(const char* oldpath, int newdirfd, const char* newpath)
|
|||
{
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
|
||||
char* newpathcopy = GetStringFromUser(newpath);
|
||||
if ( !newpathcopy )
|
||||
char* newpath_copy = GetStringFromUser(newpath);
|
||||
if ( !newpath_copy )
|
||||
return -1;
|
||||
const char* newrelpath = newpathcopy;
|
||||
Ref<Descriptor> newfrom(PrepareLookup(&newrelpath, newdirfd));
|
||||
if ( !newfrom ) { delete[] newpathcopy; return -1; }
|
||||
char* oldpath_copy = GetStringFromUser(oldpath);
|
||||
if ( !oldpath_copy )
|
||||
return delete[] newpath_copy, -1;
|
||||
|
||||
char* final_elem;
|
||||
Ref<Descriptor> dir = OpenDirContainingPath(&ctx, newfrom, newpathcopy,
|
||||
&final_elem);
|
||||
delete[] newpathcopy;
|
||||
if ( !dir )
|
||||
return -1;
|
||||
const char* newrel_path = newpath_copy;
|
||||
Ref<Descriptor> newfrom(PrepareLookup(&newrel_path, newdirfd));
|
||||
if ( !newfrom )
|
||||
return delete[] newpath_copy, -1;
|
||||
|
||||
char* oldpathcopy = GetStringFromUser(oldpath);
|
||||
if ( !oldpathcopy ) { delete[] final_elem; return -1; }
|
||||
int ret = newfrom->symlink(&ctx, oldpath, newrel_path);
|
||||
|
||||
int ret = (errno = EPERM, -1);
|
||||
|
||||
delete[] oldpathcopy;
|
||||
delete[] final_elem;
|
||||
delete[] oldpath_copy;
|
||||
delete[] newpath_copy;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int sys_settermmode(int fd, unsigned mode)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
|
@ -698,8 +692,7 @@ static ssize_t sys_readlinkat(int dirfd, const char* path, char* buf, size_t siz
|
|||
const char* relpath = pathcopy;
|
||||
Ref<Descriptor> from = PrepareLookup(&relpath, dirfd);
|
||||
if ( !from ) { delete[] pathcopy; return -1; }
|
||||
// TODO: Open the symbolic link, instead of what it points to!
|
||||
Ref<Descriptor> desc = from->open(&ctx, relpath, O_READ);
|
||||
Ref<Descriptor> desc = from->open(&ctx, relpath, O_READ | O_SYMLINK_NOFOLLOW);
|
||||
delete[] pathcopy;
|
||||
if ( !desc )
|
||||
return -1;
|
||||
|
|
|
@ -110,11 +110,7 @@ int main(int argc, char* argv[])
|
|||
if ( force )
|
||||
unlink(newname);
|
||||
|
||||
if ( symbolic )
|
||||
fprintf(stderr, "%s: symbolic links are not supported, creating hard "
|
||||
"link instead\n", argv0);
|
||||
|
||||
int ret = link(oldname, newname);
|
||||
int ret = (symbolic ? symlink : link)(oldname, newname);
|
||||
if ( ret == 0 )
|
||||
{
|
||||
if ( verbose )
|
||||
|
|
Loading…
Reference in a new issue