Add writing to existing files and overwriting `cp`

Freywar Ulvnaudgari 1 month ago
parent caa22ded0f
commit 75ea2d26b3
  1. 1
      build.sh
  2. 39
      meson.build
  3. 494
      src/kernel/fat16.c
  4. 6
      src/kernel/fat16.h
  5. 12
      src/kernel/fs.c
  6. 6
      src/kernel/fs.h
  7. 10
      src/kernel/keyboard.c
  8. 8
      src/kernel/pipe.c
  9. 6
      src/kernel/stream.h
  10. 9
      src/kernel/syscall.c
  11. 1
      src/kernel/syscall.h
  12. 10
      src/kernel/vga.c
  13. 55
      src/user/app/cp/cp.c
  14. 6
      src/user/syscall.asm
  15. 2
      src/user/syscall.h

@ -21,3 +21,4 @@ mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/shell ::bin/s
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/echo ::bin/echo
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/ls ::bin/ls
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cat ::bin/cat
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cp ::bin/cp

@ -310,3 +310,42 @@ custom_target(
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
cp_start = custom_target(
'cp_start',
input: 'src/user/start.asm',
output: 'cp_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
cp_syscall = custom_target(
'cp_syscall',
input: 'src/user/syscall.asm',
output: 'cp_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
cp_elf = executable(
'cp.elf',
sources: [cp_start, cp_syscall, lib_sources, 'src/user/app/cp/cp.c'],
c_args: [
'-ffreestanding',
'-nostdlib',
'-fno-stack-protector',
'-mcmodel=large',
'-DVERSION="' + meson.project_version() + '"',
],
link_args: [
'-T', meson.project_source_root() / 'src/user/linker.ld',
'-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
custom_target(
'cp',
input: cp_elf,
output: 'cp',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)

@ -33,15 +33,96 @@ typedef struct __attribute__((packed)) {
uint32_t size;
} fat16_dir_entry_t;
#define MAX_INODES 256
typedef struct {
uint32_t refs;
uint16_t first_cluster;
uint32_t size;
uint16_t dir_cluster;
uint16_t dir_index;
uint8_t valid;
} fat16_inode_t;
static fat16_inode_t inodes[MAX_INODES];
static fat16_inode_t *inode_create(uint16_t first_cluster, uint32_t size, uint16_t dir_cluster, uint16_t dir_index) {
for (uint64_t i = 0; i < MAX_INODES; i++) {
if (!inodes[i].valid) {
inodes[i] = (fat16_inode_t){
.refs = 1,
.first_cluster = first_cluster,
.size = size,
.dir_cluster = dir_cluster,
.dir_index = dir_index,
.valid = 1,
};
return &inodes[i];
}
}
return NUL;
}
static fat16_inode_t *inode_get(uint32_t dir_cluster, uint16_t dir_index) {
for (uint64_t i = 0; i < MAX_INODES; i++) {
if (inodes[i].valid && inodes[i].dir_cluster == dir_cluster && inodes[i].dir_index == dir_index) {
return &inodes[i];
}
}
return NUL;
}
static fat16_inode_t *inode_use(uint16_t first_cluster, uint32_t size, uint16_t dir_cluster, uint16_t dir_index) {
fat16_inode_t *result = inode_get(dir_cluster, dir_index);
if (!result) {
result = inode_create(first_cluster, size, dir_cluster, dir_index);
} else {
result->refs++;
}
return result;
}
static void inode_free(fat16_inode_t *inode) {
inode->refs--;
if (!inode->refs) {
for (uint64_t i = 0; i < MAX_INODES; i++) {
if (&inodes[i] == inode) {
inodes[i].valid = 0;
break;
}
}
}
}
typedef struct {
fs_node_t base;
fat16_dir_entry_t entry;
fat16_inode_t *inode;
} fat16_node_t;
static fat16_bpb_t bpb; // Assuming one partition.
static uint32_t data_start;
static fs_node_t *fs = NUL;
static uint16_t *fat = NUL;
fs_node_t *fat16_mount() { // Assuming one partition.
uint8_t sector[512];
ata_read_sectors(FIRST_PARTITION_SECTOR, 1, &sector);
memory_copy(sector + 11, sizeof(fat16_bpb_t), &bpb);
data_start = FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.sectors_per_fat * bpb.fats_count +
(bpb.root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
fat16_node_t *node = memory_allocate(sizeof(fat16_node_t));
node->base.type = FAT16;
node->base.name[0] = '/';
node->base.size = sizeof(fat16_dir_entry_t) * bpb.root_entry_count;
node->base.is_dir = 1;
node->inode = inode_use(0, node->base.size, 0, UINT16_MAX);
if (!node->inode) {
memory_free(node);
return NUL;
}
return fs = (fs_node_t *)node;
}
static void to_8_3(const char *name, char *output) {
memory_set(' ', 11, output);
output[11] = '\0';
@ -75,18 +156,6 @@ static void from_8_3(const char *name, const char *extension, char *output) {
}
}
fs_node_t *fat16_mount() { // Assuming one partition.
uint8_t sector[512];
ata_read_sectors(FIRST_PARTITION_SECTOR, 1, &sector);
memory_copy(sector + 11, sizeof(fat16_bpb_t), &bpb);
fat16_node_t *node = memory_allocate(sizeof(fat16_node_t));
node->base.type = FAT16;
node->base.name[0] = node->entry.name[0] = '/';
node->base.size = node->entry.size = sizeof(fat16_dir_entry_t) * bpb.root_entry_count;
node->base.is_dir = 1;
return fs = (fs_node_t *)node;
}
static void ensure_fat() {
ASSERT(bpb.sectors_per_fat < 256, "ensure_fat: big FAT not implemented")
if (!fat) {
@ -95,17 +164,32 @@ static void ensure_fat() {
}
}
static fat16_dir_entry_t *load_directory(fat16_node_t *directory) {
static uint16_t allocate_cluster() {
ensure_fat();
for (uint16_t i = 2; i < bpb.sectors_per_fat * SECTOR_SIZE / 2; i++) {
if (fat[i] == 0x0000) {
fat[i] = 0xFFFF;
return i;
}
}
return 0;
}
static void flush_fat() {
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat);
}
static fat16_dir_entry_t *read_directory(uint16_t dir_cluster) {
fat16_dir_entry_t *entries;
if (!directory->entry.first_cluster) {
uint8_t sectors = (uint8_t)((directory->base.size + SECTOR_SIZE - 1) / SECTOR_SIZE);
if (!dir_cluster) {
uint8_t sectors = (uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE);
entries = memory_allocate(sectors * SECTOR_SIZE + sizeof(fat16_dir_entry_t)); // One extra as null terminator.
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, sectors, entries);
} else {
ensure_fat();
uint16_t next_cluster = directory->entry.first_cluster;
uint16_t next_cluster = dir_cluster;
uint32_t cluster_count = 0;
while (next_cluster < 0xFFF8) {
cluster_count++;
@ -115,12 +199,9 @@ static fat16_dir_entry_t *load_directory(fat16_node_t *directory) {
memory_allocate(cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE + sizeof(fat16_dir_entry_t)); // One extra as null terminator.
uint8_t *chunk = (uint8_t *)entries;
next_cluster = directory->entry.first_cluster;
next_cluster = dir_cluster;
while (next_cluster < 0xFFF8) {
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.sectors_per_fat * bpb.fats_count +
(bpb.root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE +
bpb.sectors_per_cluster * (next_cluster - 2),
bpb.sectors_per_cluster, chunk);
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk);
chunk += bpb.sectors_per_cluster * SECTOR_SIZE;
next_cluster = fat[next_cluster];
}
@ -129,50 +210,80 @@ static fat16_dir_entry_t *load_directory(fat16_node_t *directory) {
return entries;
}
static fs_node_t *open_entry(const char *name, const fat16_dir_entry_t *entry) {
static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t index) {
const fat16_dir_entry_t *entry = &entries[index];
if (!entry->name[0]) {
return NUL;
}
fat16_node_t *result = memory_allocate(sizeof(fat16_node_t));
memory_copy((char *)name, string_length(name) + 1, &(result->base.name));
result->base.type = FAT16;
from_8_3(entry->name, entry->ext, result->base.name);
result->base.size = entry->size;
result->base.is_dir = entry->attributes & ATTRIBUTE_SUBDIRECTORY;
memory_copy((fat16_dir_entry_t *)entry, sizeof(fat16_dir_entry_t), (uint8_t *)result + sizeof(fs_node_t));
result->inode = inode_use(entry->first_cluster, entry->size, dir_cluster, index);
if (!result->inode) {
memory_free(result);
return NUL;
}
return (fs_node_t *)result;
}
static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entries) {
if (!dir_cluster) {
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat,
(uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE), entries);
} else {
ensure_fat();
// Assuming no entries were added or removed.
uint8_t *chunk = (uint8_t *)entries;
uint16_t next_cluster = dir_cluster;
while (next_cluster < 0xFFF8) {
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk);
chunk += bpb.sectors_per_cluster * SECTOR_SIZE;
next_cluster = fat[next_cluster];
}
}
}
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name) {
ASSERT(directory->type == FAT16, "fat16_open_by: directory is not FAT16");
ASSERT(directory->is_dir, "fat16_open_by: directory is not a directory");
if (directory->type != FAT16 || !directory->is_dir) {
return NUL;
}
char name_8_3[12];
to_8_3(name, name_8_3);
fat16_dir_entry_t *entries = load_directory((fat16_node_t *)directory);
fat16_dir_entry_t *entries = read_directory(((fat16_node_t *)directory)->inode->first_cluster);
fat16_dir_entry_t *entry = entries;
uint16_t index = 0;
while (entry->name[0]) {
if ((uint8_t)entry->name[0] != 0xE5 && (uint8_t)entry->attributes != 0x0F && bytes_equal(name_8_3, (char *)entry, 11)) {
break;
}
entry++;
index++;
}
fs_node_t *result = open_entry(name, entry);
fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, index);
memory_free(entries);
return result;
}
fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index) {
ASSERT(directory->type == FAT16, "fat16_open_at: directory is not FAT16");
ASSERT(directory->is_dir, "fat16_open_at: directory is not a directory");
if (directory->type != FAT16 || !directory->is_dir) {
return NUL;
}
fat16_dir_entry_t *entries = load_directory((fat16_node_t *)directory);
fat16_dir_entry_t *entries = read_directory(((fat16_node_t *)directory)->inode->first_cluster);
uint64_t ei = 0, vi = 0;
uint16_t ei = 0, vi = 0;
while (entries[ei].name[0]) {
if ((uint8_t)entries[ei].name[0] != 0xE5 && (uint8_t)entries[ei].attributes != 0x0F) {
if (vi == index) {
@ -183,14 +294,7 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index) {
ei++;
}
if (!entries[ei].name[0]) {
return NUL;
}
char name[13];
from_8_3(entries[ei].name, entries[ei].ext, name);
fs_node_t *result = open_entry(name, entries + ei);
fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, ei);
memory_free(entries);
return result;
}
@ -198,30 +302,228 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index) {
fs_node_t *fat16_open_again(const fs_node_t *source) {
fs_node_t *result = memory_allocate(sizeof(fat16_node_t));
memory_copy(source, sizeof(fat16_node_t), result);
((fat16_node_t *)result)->inode->refs++;
return result;
}
uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to) {
fat16_node_t *fat_file = (fat16_node_t *)file;
if (fat_file->base.type != FAT16 || fat_file->base.is_dir) {
return (uint64_t)-1;
}
if (offset >= fat_file->inode->size) {
return 0;
}
if (offset + bytes >= fat_file->inode->size) {
bytes = fat_file->inode->size - offset;
}
ensure_fat();
uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
uint32_t next_cluster = fat_file->inode->first_cluster;
while (offset >= cluster_size) {
next_cluster = fat[next_cluster];
offset -= cluster_size;
}
uint32_t readden = 0;
uint8_t *cursor = to;
uint8_t *tmp = memory_allocate(cluster_size);
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset;
memory_copy(tmp + offset, prefix_size, cursor);
bytes -= prefix_size;
readden += prefix_size;
cursor += prefix_size;
next_cluster = fat[next_cluster];
while (bytes >= cluster_size) {
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, cursor);
bytes -= cluster_size;
readden += cluster_size;
cursor += cluster_size;
next_cluster = fat[next_cluster];
}
if (bytes) {
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
memory_copy(tmp, bytes, cursor);
readden += bytes;
}
memory_free(tmp);
return readden;
}
uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes) {
fat16_node_t *fat_file = (fat16_node_t *)file;
if (fat_file->base.type != FAT16 || fat_file->base.is_dir) {
return (uint64_t)-1;
}
ensure_fat();
if (!fat_file->inode->first_cluster) {
fat_file->inode->first_cluster = allocate_cluster();
}
uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
uint32_t next_cluster = fat_file->inode->first_cluster;
uint32_t allocated = cluster_size;
while (allocated < offset + bytes) {
if (fat[next_cluster] >= 0xFFF8) {
fat[next_cluster] = allocate_cluster();
}
next_cluster = fat[next_cluster];
allocated += cluster_size;
}
flush_fat();
cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
next_cluster = fat_file->inode->first_cluster;
while (offset >= cluster_size) {
next_cluster = fat[next_cluster];
offset -= cluster_size;
}
uint32_t written = 0;
const uint8_t *cursor = from;
uint8_t *tmp = memory_allocate(cluster_size);
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset;
memory_copy(cursor, prefix_size, tmp + offset);
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
bytes -= prefix_size;
written += prefix_size;
cursor += prefix_size;
next_cluster = fat[next_cluster];
while (bytes >= cluster_size) {
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, cursor);
bytes -= cluster_size;
written += cluster_size;
cursor += cluster_size;
next_cluster = fat[next_cluster];
}
if (bytes) {
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
memory_copy(cursor, bytes, tmp);
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
written += bytes;
}
memory_free(tmp);
if (offset + written > fat_file->inode->size) {
fat_file->inode->size = offset + written;
fat16_dir_entry_t *entries = read_directory(fat_file->inode->dir_cluster);
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster;
entries[fat_file->inode->dir_index].size = fat_file->inode->size;
write_directory(fat_file->inode->dir_cluster, entries);
memory_free(entries);
}
return written;
}
uint64_t fat16_truncate(fs_node_t *file, uint32_t size) {
fat16_node_t *fat_file = (fat16_node_t *)file;
if (fat_file->base.type != FAT16 || fat_file->base.is_dir) {
return (uint64_t)-1;
}
if (file->size == size) {
return size;
} else if (file->size < size) {
uint32_t diff = size - file->size;
uint8_t *tmp = memory_allocate(diff);
uint64_t written = fat16_write(file, file->size, tmp, diff);
memory_free(tmp);
return written == (uint64_t)-1 ? (uint64_t)-1 : file->size + written;
} else if (file->size > size) {
uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
uint32_t prev_cluster = 0;
uint32_t next_cluster = fat_file->inode->first_cluster;
ensure_fat();
uint32_t allocated = 0;
while (allocated < size) {
prev_cluster = next_cluster;
next_cluster = fat[next_cluster];
allocated += cluster_size;
}
if (prev_cluster) {
fat[prev_cluster] = 0xFFFF;
} else {
fat_file->inode->first_cluster = 0;
}
do {
uint32_t swap = fat[next_cluster];
fat[next_cluster] = 0;
next_cluster = swap;
} while (next_cluster < 0xFFF8);
flush_fat();
fat_file->inode->size = size;
fat16_dir_entry_t *entries = read_directory(fat_file->inode->dir_cluster);
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster;
entries[fat_file->inode->dir_index].size = fat_file->inode->size;
write_directory(fat_file->inode->dir_cluster, entries);
memory_free(entries);
return size;
}
return (uint64_t)-1;
}
typedef struct {
stream_t stream;
fs_node_t *node;
uint64_t offset;
uint32_t offset;
} fat16_file_stream_t;
static uint64_t file_stream_write(__attribute__((unused)) const stream_t *self, __attribute__((unused)) const char *from,
__attribute__((unused)) uint64_t bytes) {
return (uint64_t)-1;
static uint64_t file_stream_write(stream_t *self, const char *from, uint64_t bytes) {
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self;
uint64_t written = fat16_write(ffs->node, ffs->offset, from, bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes);
if (written != (uint64_t)-1) {
ffs->offset += written;
}
return written;
}
static uint64_t file_stream_read(const stream_t *self, uint64_t max, char *to) {
static uint64_t file_stream_read(stream_t *self, uint64_t max, char *to) {
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self;
if (ffs->offset >= ffs->node->size) {
return 0;
uint64_t readden = fat16_read(ffs->node, ffs->offset, max > UINT32_MAX ? UINT32_MAX : (uint32_t)max, to);
if (readden != (uint64_t)-1) {
ffs->offset += readden;
}
uint64_t remaining = ffs->node->size - ffs->offset;
uint64_t to_read = remaining > max ? max : remaining;
fat16_read(ffs->node, ffs->offset, to_read, to);
ffs->offset += to_read;
return to_read;
return readden;
}
static uint64_t file_stream_truncate(stream_t *self, uint64_t size) {
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self;
uint64_t resized = fat16_truncate(ffs->node, size > UINT32_MAX ? UINT32_MAX : (uint32_t)size);
if (resized != (uint64_t)-1 && resized < ffs->offset) {
ffs->offset = (uint32_t)resized;
}
return resized;
}
static void file_stream_close(stream_t *self) {
@ -233,15 +535,15 @@ static void file_stream_close(stream_t *self) {
typedef struct {
stream_t stream;
fs_node_t *node;
uint64_t index;
uint32_t index;
} fat16_directory_stream_t;
static uint64_t directory_stream_write(__attribute__((unused)) const stream_t *self, __attribute__((unused)) const char *from,
static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from,
__attribute__((unused)) uint64_t bytes) {
return (uint64_t)-1;
}
static uint64_t directory_stream_read(const stream_t *self, uint64_t max, char *to) {
static uint64_t directory_stream_read(stream_t *self, uint64_t max, char *to) {
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self;
fs_node_t *node = fat16_open_at(fds->node, fds->index++);
if (!node) {
@ -250,11 +552,14 @@ static uint64_t directory_stream_read(const stream_t *self, uint64_t max, char *
uint64_t length = string_length(node->name);
uint64_t to_read = length + 1 > max ? max : length + 1;
memory_copy(node->name, to_read, to);
to[max - 1] = '\0';
to[to_read - 1] = '\0';
return to_read;
}
static uint64_t directory_stream_truncate(__attribute__((unused)) stream_t *self, __attribute__((unused)) uint64_t size) {
return (uint64_t)-1;
}
static void directory_stream_close(stream_t *self) {
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self;
fat16_close(fds->node);
@ -266,6 +571,7 @@ stream_t *fat16_open_stream(const fs_node_t *source) {
fat16_file_stream_t *result = memory_allocate(sizeof(fat16_file_stream_t));
result->stream.read = file_stream_read;
result->stream.write = file_stream_write;
result->stream.truncate = file_stream_truncate;
result->stream.close = file_stream_close;
result->node = fat16_open_again(source);
result->offset = 0;
@ -274,6 +580,7 @@ stream_t *fat16_open_stream(const fs_node_t *source) {
fat16_directory_stream_t *result = memory_allocate(sizeof(fat16_directory_stream_t));
result->stream.read = directory_stream_read;
result->stream.write = directory_stream_write;
result->stream.truncate = directory_stream_truncate;
result->stream.close = directory_stream_close;
result->node = fat16_open_again(source);
result->index = 0;
@ -281,68 +588,25 @@ stream_t *fat16_open_stream(const fs_node_t *source) {
}
}
void fat16_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to) {
ASSERT(file->type == FAT16, "fat16_read: file is not FAT16");
ASSERT(!file->is_dir, "fat16_read: can not read directory");
ASSERT(file->size >= offset + size, "fat16_read: offset/size are out of bounds");
ensure_fat();
fat16_node_t *fat_file = (fat16_node_t *)file;
uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
uint32_t next_cluster = fat_file->entry.first_cluster;
// Assuming filesystem is correct. TODO Check for real.
while (offset >= cluster_size) {
next_cluster = fat[next_cluster];
offset -= cluster_size;
}
uint8_t *cursor = to;
uint8_t *tmp = memory_allocate(cluster_size);
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.sectors_per_fat * bpb.fats_count +
(bpb.root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE +
bpb.sectors_per_cluster * (next_cluster - 2),
bpb.sectors_per_cluster, tmp);
uint64_t prefix_size = size <= cluster_size - offset ? size : cluster_size - offset;
memory_copy(tmp + offset, prefix_size, cursor);
size -= prefix_size;
cursor += prefix_size;
next_cluster = fat[next_cluster];
while (size >= cluster_size) {
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.sectors_per_fat * bpb.fats_count +
(bpb.root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE +
bpb.sectors_per_cluster * (next_cluster - 2),
bpb.sectors_per_cluster, cursor);
size -= cluster_size;
cursor += cluster_size;
next_cluster = fat[next_cluster];
}
if (size) {
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.sectors_per_fat * bpb.fats_count +
(bpb.root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE +
bpb.sectors_per_cluster * (next_cluster - 2),
bpb.sectors_per_cluster, tmp);
memory_copy(tmp, size, cursor);
}
memory_free(tmp);
}
void fat16_close(fs_node_t *node) {
ASSERT(node->type == FAT16, "fat16_close: node is not FAT16");
ASSERT(node != fs, "fat16_close: can not unmount FS");
if (node->type != FAT16 || node == fs) {
return;
}
inode_free(((fat16_node_t *)node)->inode);
memory_free(node);
}
void fat16_unmount(fs_node_t *node) {
ASSERT(node->type == FAT16, "fat16_unmount: node is not FAT16");
ASSERT(node == fs, "fat16_unmount: node is not filesystem");
if (node->type != FAT16 || node != fs) {
return;
}
inode_free(((fat16_node_t *)node)->inode);
memory_free(node);
if (fat) {
memory_free(fat);
fat = NUL;
}
fs = NUL;
}

@ -15,7 +15,11 @@ fs_node_t *fat16_open_again(const fs_node_t *source);
stream_t *fat16_open_stream(const fs_node_t *source);
void fat16_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to);
uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to);
uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes);
uint64_t fat16_truncate(fs_node_t *file, uint32_t size);
void fat16_close(fs_node_t *node);

@ -21,8 +21,16 @@ stream_t *fs_open_stream(const fs_node_t *source) {
return fat16_open_stream(source);
}
void fs_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to) {
fat16_read(file, offset, size, to);
void fs_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to) {
fat16_read(file, offset, bytes, to);
}
void fs_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes) {
fat16_write(file, offset, from, bytes);
}
void fs_truncate(fs_node_t *file, uint32_t size) {
fat16_truncate(file, size);
}
void fs_close(fs_node_t *node) {

@ -22,7 +22,11 @@ fs_node_t *fs_open_again(const fs_node_t *source);
stream_t *fs_open_stream(const fs_node_t *source);
void fs_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to);
void fs_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to);
void fs_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes);
void fs_truncate(fs_node_t *file, uint32_t size);
void fs_close(fs_node_t *node);

@ -51,12 +51,12 @@ static void append_sequence(const char *s) {
}
}
static uint64_t stream_write(__attribute__((unused)) const stream_t *self, __attribute__((unused)) const char *from,
static uint64_t stream_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from,
__attribute__((unused)) uint64_t bytes) {
return 0;
}
static uint64_t stream_read(__attribute__((unused)) const stream_t *self, uint64_t max, char *to) {
static uint64_t stream_read(__attribute__((unused)) stream_t *self, uint64_t max, char *to) {
while (!buffer_length) {
__asm__ volatile("sti");
process_next();
@ -79,10 +79,14 @@ static uint64_t stream_read(__attribute__((unused)) const stream_t *self, uint64
return size;
}
static uint64_t stream_truncate(__attribute__((unused)) stream_t *self, __attribute__((unused)) uint64_t size) {
return size;
}
static void stream_close(__attribute__((unused)) stream_t *self) {
}
static stream_t stream = {stream_write, stream_read, stream_close};
static stream_t stream = {stream_write, stream_read, stream_truncate, stream_close};
static void on_key(uint8_t scancode) {
const uint8_t pressed = !(scancode & 0x80);

@ -23,17 +23,17 @@ typedef struct {
pipe_t *pipe;
} pipe_write_stream_t;
static uint64_t null_read(__attribute__((unused)) const stream_t *self, __attribute__((unused)) uint64_t max,
static uint64_t null_read(__attribute__((unused)) stream_t *self, __attribute__((unused)) uint64_t max,
__attribute__((unused)) char *to) {
return 0;
}
static uint64_t null_write(__attribute__((unused)) const stream_t *self, __attribute__((unused)) const char *from,
static uint64_t null_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from,
__attribute__((unused)) uint64_t bytes) {
return 0;
}
static uint64_t pipe_read(const stream_t *self, uint64_t max, char *to) {
static uint64_t pipe_read(stream_t *self, uint64_t max, char *to) {
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
while (pipe->begin == pipe->end) {
@ -60,7 +60,7 @@ static uint64_t pipe_read(const stream_t *self, uint64_t max, char *to) {
return to_read;
}
static uint64_t pipe_write(const stream_t *self, const char *from, uint64_t bytes) {
static uint64_t pipe_write(stream_t *self, const char *from, uint64_t bytes) {
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
uint64_t written = 0;

@ -27,12 +27,14 @@
typedef struct stream stream_t;
typedef uint64_t (*stream_write_t)(const stream_t *self, const char *from, uint64_t bytes);
typedef uint64_t (*stream_read_t)(const stream_t *self, uint64_t max, char *to);
typedef uint64_t (*stream_write_t)(stream_t *self, const char *from, uint64_t bytes);
typedef uint64_t (*stream_read_t)(stream_t *self, uint64_t max, char *to);
typedef uint64_t (*stream_truncate_t)(stream_t *self, uint64_t size);
typedef void (*stream_close_t)(stream_t *self);
typedef struct stream {
stream_write_t write;
stream_read_t read;
stream_truncate_t truncate;
stream_close_t close;
} stream_t;

@ -182,6 +182,13 @@ static uint64_t close(uint64_t fd) {
return 0;
}
static uint64_t truncate(uint64_t fd, uint64_t size) {
if (fd >= MAX_FDS || !current_process->fds[fd]) {
return (uint64_t)-1;
}
return current_process->fds[fd]->truncate(current_process->fds[fd], size);
}
static void exit(exit_code_t code) {
current_process->state = PROCESS_ZOMBIE;
current_process->code = code;
@ -214,6 +221,8 @@ uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t
return open((const char *)arg1);
case SYSCALL_CLOSE:
return close(arg1);
case SYSCALL_TRUNCATE:
return truncate(arg1, arg2);
case SYSCALL_EXIT:
exit(arg1);
return 0;

@ -10,6 +10,7 @@
#define SYSCALL_WAIT 5
#define SYSCALL_OPEN 6
#define SYSCALL_CLOSE 7
#define SYSCALL_TRUNCATE 8
#define SYSCALL_EXIT 60
void syscall_init();

@ -142,7 +142,7 @@ static void on_char_received(char c) {
}
}
static uint64_t stream_write(__attribute__((unused)) const stream_t *self, const char *from, uint64_t bytes) {
static uint64_t stream_write(__attribute__((unused)) stream_t *self, const char *from, uint64_t bytes) {
uint64_t left = bytes;
while (left--) {
on_char_received(*from++);
@ -150,15 +150,19 @@ static uint64_t stream_write(__attribute__((unused)) const stream_t *self, const
return bytes;
}
static uint64_t stream_read(__attribute__((unused)) const stream_t *self, __attribute__((unused)) uint64_t max,
static uint64_t stream_read(__attribute__((unused)) stream_t *self, __attribute__((unused)) uint64_t max,
__attribute__((unused)) char *to) {
return 0;
}
static uint64_t stream_truncate(__attribute__((unused)) stream_t *self, __attribute__((unused)) uint64_t size) {
return size;
}
static void stream_close(__attribute__((unused)) stream_t *self) {
}
static stream_t stream = {stream_write, stream_read, stream_close};
static stream_t stream = {stream_write, stream_read, stream_truncate, stream_close};
stream_t *vga_init() {
clear();

@ -0,0 +1,55 @@
#include "src/lib/util.h"
#include "src/user/syscall.h"
#define BLOCK_SIZE 65536
#define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
exit_code_t main(uint64_t argc, const char **argv) {
if (argc != 3) {
PRINT_S("cp: requires source and target");
return EXIT_CODE_GENERAL_FAILURE;
}
uint64_t source = open(argv[1]);
if (source == (uint64_t)-1) {
PRINT_S("cp: source does not exist\n");
return EXIT_CODE_GENERAL_FAILURE;
}
uint64_t target = open(argv[2]);
if (target == (uint64_t)-1) {
PRINT_S("cp: target does not exist\n");
close(source);
return EXIT_CODE_GENERAL_FAILURE;
}
if (truncate(target, 0) == (uint64_t)-1) {
close(source);
close(target);
return EXIT_CODE_GENERAL_FAILURE;
}
static char buffer[BLOCK_SIZE];
uint64_t bytes;
while ((bytes = read(source, BLOCK_SIZE, buffer))) {
if (bytes == (uint64_t)-1) {
PRINT_S("cp: could not read file\n");
close(source);
close(target);
return EXIT_CODE_GENERAL_FAILURE;
}
if (write(target, buffer, bytes) == (uint64_t)-1) {
PRINT_S("cp: could not write file\n");
close(source);
close(target);
return EXIT_CODE_GENERAL_FAILURE;
}
}
close(source);
close(target);
return EXIT_CODE_OK;
}

@ -48,6 +48,12 @@ close:
syscall
ret
global truncate
truncate:
mov rax, 8
syscall
ret
global exit
exit:
mov rax, 60

@ -19,4 +19,6 @@ uint64_t open(const char *path);
uint64_t close(uint64_t fd);
uint64_t truncate(uint64_t fd, uint64_t size);
void exit(exit_code_t code);

Loading…
Cancel
Save