Skip to content

Commit

Permalink
kernel: add ftruncate() system call
Browse files Browse the repository at this point in the history
  • Loading branch information
EtchedPixels committed Jul 9, 2024
1 parent 3ca648b commit e9124ab
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 22 deletions.
95 changes: 79 additions & 16 deletions Kernel/filesys.c
Original file line number Diff line number Diff line change
Expand Up @@ -923,37 +923,89 @@ uint16_t devnum(inoptr ino)
}


/* F_trunc frees all the blocks associated with the file, if it
* is a disk file.
/*
* f_trunc_blocks frees all the blocks associated with the file, if it
* is a disk file. The blocks are freed in reverse order. This is
* very important so that they end up on the freelist in the
* order we want to allocate them.
*/
int f_trunc(register inoptr ino)
int f_trunc_blocks(register inoptr ino, uint16_t nblock)
{
register uint16_t dev;
register int_fast8_t j;
uint16_t map1 = 0;
uint16_t map2 = 0;

if (ino->c_flags & CRDONLY) {
udata.u_error = EROFS;
return -1;
}

/* Block offsets are
0-17 direct
18 256 blocks (18-273)
19 256 * 256 blocks (274-65810)
(We only allow 65535 block offset in order to keep a lot of stuff
uint16_t - FIXME to fix u writei())
We don't support triple indirect blocks.
When we are called nblock is the number of blocks that will
remain in the file when we truncate it
We set map1 to the number of blocks we must purge for single
indirect. We set map2 for the number of blocks we must purge
of double indirect.
freeblk frees full subblocks above the block passed, and then frees
blocks >> 8 on the last iteration to partially clear the last set
*/

if (nblock > 17 && nblock < 274)
map1 = (nblock - 18) << 8;
else if (nblock > 273)
map2 = nblock - 273;
dev = ino->c_dev;

/* FIXME: ideally zero the indirect pointers before we write the
free lists */

/* First deallocate the double indirect blocks */
freeblk(dev, ino->c_node.i_addr[19], 2);
freeblk(dev, ino->c_node.i_addr[19], 2, map2);
if (map2)
ino->c_node.i_addr[19] = 0;

/* Also deallocate the indirect blocks */
freeblk(dev, ino->c_node.i_addr[18], 1);
freeblk(dev, ino->c_node.i_addr[18], 1, map1);
if (map1 == 0 && map2 == 0) /* ???? should this just be if map1 */
ino->c_node.i_addr[18] = 0;

/* Finally, free the direct blocks */
for(j = 17; j >= 0; --j)
freeblk(dev, ino->c_node.i_addr[j], 0);

memset((uint8_t *)ino->c_node.i_addr, 0, sizeof(ino->c_node.i_addr));
/* FIXME: use pointers for efficiency ? */
/* At this point nblock is definitely < 0x8000 so forcing a signed
compare does what we want */
for(j = 17; j >= (int)nblock; --j) {
freeblk(dev, ino->c_node.i_addr[j], 0, 0);
ino->c_node.i_addr[j] = 0;
}

ino->c_flags |= CDIRTY;
ino->c_node.i_size = 0;
return 0;
}


/* Truncate a file back to nothing using f_trunc_blocks and then write
the inode size as 0 */
int f_trunc(regptr inoptr ino)
{
/* Is it worth checking size already 0 ? */
if (f_trunc_blocks(ino, 0))
return -1;
ino->c_node.i_size = 0;
return 0;
}

/* Companion function to f_trunc().
This is the one case where we can't hide the difference between an internal
Expand All @@ -963,11 +1015,12 @@ int f_trunc(register inoptr ino)
This is annoying and it would be nice one day to find a clean solution */

#ifdef CONFIG_BLKBUF_EXTERNAL
void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level)
void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level, uint16_t nblock)
{
struct blkbuf *buf;
regptr blkno_t *bn;
int16_t j;
int_fast8_t nblock1 = nblock >> 8;

if(!blk)
return;
Expand All @@ -978,9 +1031,12 @@ void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level)
corrupt_fs(dev);
return;
}
for(j = BLKSIZE / 2 - 1; j >= 0; --j) {
for(j = BLKSIZE / 2 - 1; j >= nblock1; --j) {
uint8_t b = 0;
if (j == nblock1)
b = nblock & 0xFF;
blktok(&bn, buf, j * sizeof(blkno_t), sizeof(blkno_t));
freeblk(dev, bn[j], level-1);
freeblk(dev, bn[j], level - 1, b);
}
brelse(buf);
}
Expand All @@ -992,11 +1048,12 @@ void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level)

#else

void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level)
void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level, uint16_t nblock)
{
struct blkbuf *buf;
regptr blkno_t *bn;
int16_t j;
int_fast8_t nblock1 = nblock >> 8;

if(!blk)
return;
Expand All @@ -1008,8 +1065,14 @@ void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level)
return;
}
bn = blkptr(buf, 0, BLKSIZE);
for(j = BLKSIZE / 2 - 1; j >= 0; --j)
freeblk(dev, bn[j], level-1);
for(j = BLKSIZE / 2 - 1; j >= 0; --j) {
/* When we hit nblock1 we are doing the final partial clear, so
only tell the child freeblk to do a partial clear */
uint_fast8_t b = 0;
if (j == nblock1)
b = nblock & 0xFF;
freeblk(dev, bn[j], level-1, b);
}
brelse(buf);
}
#ifdef CONFIG_TRIM
Expand Down
2 changes: 1 addition & 1 deletion Kernel/include/kdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ extern struct runload loadavg[];
#ifdef CONFIG_LEVEL_2
#define FUZIX_SYSCALL_COUNT 80
#else
#define FUZIX_SYSCALL_COUNT 67
#define FUZIX_SYSCALL_COUNT 68
#endif

typedef arg_t (*syscall_t)(void);
Expand Down
4 changes: 3 additions & 1 deletion Kernel/include/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -1032,8 +1032,9 @@ extern void i_deref(inoptr ino);
extern void corrupt_fs(uint16_t devno);
extern void wr_inode(inoptr ino);
extern bool isdevice(inoptr ino);
extern int f_trunc_blocks(inoptr ino, uint16_t nblock);
extern int f_trunc(inoptr ino);
extern void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level);
extern void freeblk(uint16_t dev, blkno_t blk, uint_fast8_t level, uint16_t nblock);
extern blkno_t bmap(inoptr ip, blkno_t bn, unsigned int rwflg);
extern void validblk(uint16_t dev, blkno_t num);
extern inoptr getinode(uint_fast8_t uindex);
Expand Down Expand Up @@ -1317,6 +1318,7 @@ extern arg_t _sched_yield(void); /* FUZIX system call 62 */
extern arg_t _acct(void); /* FUZIX system call 63 */
extern arg_t _memalloc(void); /* FUZIX system call 64 */
extern arg_t _memfree(void); /* FUZIX system call 65 */
extern arg_t _ftruncate(void); /* FUZIX system call 67 */

#if defined(CONFIG_32BIT)
#include "kernel32.h"
Expand Down
4 changes: 2 additions & 2 deletions Kernel/include/syscall_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const char *syscall_name[NR_SYSCALL] = {
"memalloc",
"memfree",
"__netcall",
"_nosys67",
"_ftruncate",
"_nosys68",
"_nosys69",
"_nosys70",
Expand Down Expand Up @@ -153,7 +153,7 @@ int syscall_args[NR_SYSCALL] = {
1, //memalloc
1, //memfree
1, //netcall
0, //nosys 67
2, //ftruncate
0, //nosys 68
0, //nosys 69
0, //nosys 70
Expand Down
4 changes: 2 additions & 2 deletions Kernel/kdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ const syscall_t syscall_dispatch[FUZIX_SYSCALL_COUNT] = {
#else
_nosys,
#endif
_ftruncate, /* Fuzix system call 67 */
#if defined(CONFIG_LEVEL_2)
_nosys, /* 67-71 reserved */
_nosys,
_nosys, /* 68-71 reserved */
_nosys,
_nosys,
_nosys,
Expand Down
44 changes: 44 additions & 0 deletions Kernel/syscall_fs3.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,3 +439,47 @@ arg_t _flock(void)

#undef file
#undef lockop

/*******************************************
ftruncate (file, offset) Function call 67
int16_t file;
uint32_t *offset;
********************************************/
#define file (uint16_t)udata.u_argn
#define offset (uint32_t *)udata.u_argn1

/* We copy the 32bit offset in and out rather than passing it
as a 32bit OS might */
arg_t _ftruncate(void)
{
register inoptr ino;
register struct oft *o;
off_t n;

if (uget(offset, &n, sizeof(n)))
return -1;

if ((ino = getinode(file)) == NULLINODE)
return (-1);

o = &of_tab[udata.u_files[file]];
if (n < 0 || (HIBYTE32(n) & BLKOVERSIZE32) ||
O_ACCMODE(o->o_access) == O_RDONLY ||
getmode(ino) != MODE_R(F_REG)) {
udata.u_error = EINVAL;
return -1;
}

if (n == ino->c_node.i_size)
return 0;
if (n < ino->c_node.i_size)
f_trunc_blocks(ino, BLOCK(n + BLKSIZE - 1));
ino->c_node.i_size = n;
setftime(ino, M_TIME | C_TIME);
wr_inode(ino);
return 0;
}

#undef file
#undef offset
#undef flag

0 comments on commit e9124ab

Please sign in to comment.