[fs][fat] Implement first implementation of file create
Limitations: Only supports simple 8.3 file names Cannot create with size > 0 Timestamp is bogus
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <lk/cpp.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/trace.h>
|
||||
#include <ctype.h>
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -37,13 +38,11 @@ struct fat_dir_cookie {
|
||||
static const uint32_t index_eod = 0xffffffff;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// walk one entry into the dir, starting at byte offset into the directory block iterator.
|
||||
// both dbi and offset will be modified during the call.
|
||||
// filles out the entry and returns a pointer into the passed in buffer in out_filename.
|
||||
// NOTE: *must* pass at least a MAX_FILE_NAME_LEN byte char pointer in the filename_buffer slot.
|
||||
status_t fat_find_next_entry(fat_fs *fat, file_block_iterator &dbi, uint32_t &offset, dir_entry *entry,
|
||||
static status_t fat_find_next_entry(fat_fs *fat, file_block_iterator &dbi, uint32_t &offset, dir_entry *entry,
|
||||
char filename_buffer[MAX_FILE_NAME_LEN], char **out_filename) {
|
||||
|
||||
DEBUG_ASSERT(entry && filename_buffer && out_filename);
|
||||
@@ -69,7 +68,7 @@ status_t fat_find_next_entry(fat_fs *fat, file_block_iterator &dbi, uint32_t &of
|
||||
|
||||
// walk within a sector
|
||||
while (offset < fat->info().bytes_per_sector) {
|
||||
LTRACEF_LEVEL(2, "looking at offset %u\n", offset);
|
||||
LTRACEF_LEVEL(2, "looking at offset %#x\n", offset);
|
||||
const uint8_t *ent = dbi.get_bcache_ptr(offset);
|
||||
if (ent[0] == 0) { // no more entries
|
||||
// we're completely done
|
||||
@@ -206,10 +205,11 @@ status_t fat_find_next_entry(fat_fs *fat, file_block_iterator &dbi, uint32_t &of
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
status_t fat_find_file_in_dir(fat_fs *fat, uint32_t starting_cluster, const char *name, dir_entry *entry, uint32_t *found_offset) {
|
||||
static status_t fat_find_file_in_dir(fat_fs *fat, uint32_t starting_cluster, const char *name, dir_entry *entry, uint32_t *found_offset) {
|
||||
LTRACEF("start_cluster %u, name '%s', out entry %p\n", starting_cluster, name, entry);
|
||||
|
||||
DEBUG_ASSERT(fat->lock.is_held());
|
||||
DEBUG_ASSERT(entry);
|
||||
|
||||
// cache the length of the string we're matching against
|
||||
const size_t namelen = strlen(name);
|
||||
@@ -237,15 +237,15 @@ status_t fat_find_file_in_dir(fat_fs *fat, uint32_t starting_cluster, const char
|
||||
// see if we've matched an entry
|
||||
if (filenamelen == namelen && !strnicmp(name, filename, filenamelen)) {
|
||||
// we have, return with a good status
|
||||
*found_offset = offset;
|
||||
if (found_offset) {
|
||||
*found_offset = offset;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
status_t fat_walk(fat_fs *fat, const char *path, dir_entry *out_entry, dir_entry_location *loc) {
|
||||
status_t fat_dir_walk(fat_fs *fat, const char *path, dir_entry *out_entry, dir_entry_location *loc) {
|
||||
LTRACEF("path %s\n", path);
|
||||
|
||||
DEBUG_ASSERT(fat->lock.is_held());
|
||||
@@ -321,14 +321,244 @@ status_t fat_walk(fat_fs *fat, const char *path, dir_entry *out_entry, dir_entry
|
||||
}
|
||||
} else {
|
||||
// we got a hit at the terminal entry of the path, pass it out to the caller as a success
|
||||
*out_entry = entry;
|
||||
loc->starting_dir_cluster = dir_start_cluster;
|
||||
loc->dir_offset = found_offset;
|
||||
if (out_entry) {
|
||||
*out_entry = entry;
|
||||
}
|
||||
if (loc) {
|
||||
loc->starting_dir_cluster = dir_start_cluster;
|
||||
loc->dir_offset = found_offset;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// splits a path into the part of it leading up to the last element and the last element
|
||||
// if the leading part is zero length, return a single "/" element
|
||||
// will modify string passed in
|
||||
// TODO: write unit test
|
||||
static void split_path(char *path, const char **leading_path, const char **last_element) {
|
||||
char *last_slash = strrchr(path, '/');
|
||||
if (last_slash) {
|
||||
*last_slash = 0;
|
||||
if (path[0] != 0) {
|
||||
*leading_path = path;
|
||||
} else {
|
||||
*leading_path = "/";
|
||||
}
|
||||
*last_element = last_slash + 1;
|
||||
} else {
|
||||
*leading_path = "/";
|
||||
*last_element = path;
|
||||
}
|
||||
}
|
||||
|
||||
// construct a short file name from the incoming name
|
||||
// the sfn is padded out with spaces the same way a real FAT entry is
|
||||
// TODO: write unit test
|
||||
static status_t name_to_short_file_name(char sfn[8 + 3 + 1], const char *name) {
|
||||
// zero length inputs don't fly
|
||||
if (name[0] == 0) {
|
||||
return ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// start off with a spaced out sfn
|
||||
memset(sfn, ' ', 8 + 3);
|
||||
sfn[8 + 3] = 0;
|
||||
|
||||
size_t input_pos = 0;
|
||||
size_t output_pos = 0;
|
||||
|
||||
// pick out the 8 entry part
|
||||
for (auto i = 0; i < 8; i++) {
|
||||
char c = name[input_pos];
|
||||
if (c == 0) {
|
||||
break;
|
||||
} else if (c == '.') {
|
||||
output_pos = 8;
|
||||
break;
|
||||
} else {
|
||||
sfn[output_pos++] = toupper(c);
|
||||
input_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
// at this point input pos had better be looking at a . or a null
|
||||
if (name[input_pos] == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (name[input_pos] != '.') {
|
||||
return ERR_INVALID_ARGS;
|
||||
}
|
||||
input_pos++;
|
||||
|
||||
for (auto i = 0; i < 3; i++) {
|
||||
char c = name[input_pos];
|
||||
if (c == 0) {
|
||||
break;
|
||||
} else if (c == '.') {
|
||||
// can only see '.' once
|
||||
return ERR_INVALID_ARGS;
|
||||
} else {
|
||||
sfn[output_pos++] = toupper(c);
|
||||
input_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
// at this point we should be looking at the end of the input string
|
||||
if (name[input_pos] != 0) {
|
||||
return ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t fat_dir_allocate(fat_fs *fat, const char *path, const fat_attribute attr, const uint32_t starting_cluster, const uint32_t size, dir_entry_location *loc) {
|
||||
LTRACEF("path %s\n", path);
|
||||
|
||||
DEBUG_ASSERT(fat->lock.is_held());
|
||||
|
||||
// trim the last segment off the path, splitting into stuff leading up to the last segment and the last segment
|
||||
char local_path[FS_MAX_FILE_LEN + 1];
|
||||
strlcpy(local_path, path, FS_MAX_FILE_LEN);
|
||||
|
||||
const char *leading_path;
|
||||
const char *last_element;
|
||||
split_path(local_path, &leading_path, &last_element);
|
||||
|
||||
DEBUG_ASSERT(leading_path && last_element);
|
||||
|
||||
LTRACEF("path is now split into %s and %s\n", leading_path, last_element);
|
||||
|
||||
// find the starting directory cluster of the container directory
|
||||
// 0 may mean root dir on fat12/16
|
||||
uint32_t starting_dir_cluster;
|
||||
if (strcmp(leading_path, "/") == 0) {
|
||||
// root dir is a special case since we know where to start
|
||||
if (fat->info().root_cluster) {
|
||||
starting_dir_cluster = fat->info().root_cluster;
|
||||
} else {
|
||||
// fat 12/16 has a linear root dir, cluster 0 is a special case to fat_find_file_in_dir below
|
||||
starting_dir_cluster = 0;
|
||||
}
|
||||
} else {
|
||||
// walk to find the containing directory
|
||||
dir_entry entry;
|
||||
dir_entry_location dir_loc;
|
||||
status_t err = fat_dir_walk(fat, local_path, &entry, &dir_loc);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// verify it's a directory
|
||||
if (entry.attributes != fat_attribute::directory) {
|
||||
return ERR_BAD_PATH;
|
||||
}
|
||||
|
||||
LTRACEF("found containing dir at %u:%u: starting cluster %u\n", dir_loc.starting_dir_cluster, dir_loc.dir_offset, entry.start_cluster);
|
||||
|
||||
starting_dir_cluster = entry.start_cluster;
|
||||
if (starting_dir_cluster < 2 || starting_dir_cluster >= fat->info().total_clusters) {
|
||||
TRACEF("directory entry contains out of bounds cluster %u\n", starting_dir_cluster);
|
||||
return ERR_BAD_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
LTRACEF("starting dir cluster of parent dir %u\n", starting_dir_cluster);
|
||||
|
||||
// verify the file doesn't already exist
|
||||
dir_entry entry;
|
||||
status_t err = fat_find_file_in_dir(fat, starting_dir_cluster, last_element, &entry, nullptr);
|
||||
if (err >= 0) {
|
||||
// we found it, cant create a new file in its place
|
||||
return ERR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
// TODO: handle long file names
|
||||
char sfn[8 + 3 + 1];
|
||||
err = name_to_short_file_name(sfn, last_element);
|
||||
if (err < 0) {
|
||||
// if we couldn't convert to a SFN trivially, abort
|
||||
return err;
|
||||
}
|
||||
|
||||
LTRACEF("short file name '%s'\n", sfn);
|
||||
|
||||
// now we have a starting cluster for the containing directory and proof that it doesn't already exist.
|
||||
// start walking to find a free slot
|
||||
file_block_iterator dbi(fat, starting_dir_cluster);
|
||||
err = dbi.next_sectors(0);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t dir_offset = 0;
|
||||
uint32_t sector_offset = 0;
|
||||
for (;;) {
|
||||
if (LOCAL_TRACE >= 2) {
|
||||
LTRACEF("dir sector:\n");
|
||||
hexdump8_ex(dbi.get_bcache_ptr(0), fat->info().bytes_per_sector, 0);
|
||||
}
|
||||
|
||||
// walk within a sector
|
||||
while (sector_offset < fat->info().bytes_per_sector) {
|
||||
LTRACEF_LEVEL(2, "looking at offset %#x\n", sector_offset);
|
||||
uint8_t *ent = dbi.get_bcache_ptr(sector_offset);
|
||||
if (ent[0] == 0xe5 || ent[0] == 0) {
|
||||
// deleted or last entry in the list
|
||||
LTRACEF("found usable at offset %#x\n", sector_offset);
|
||||
if (LOCAL_TRACE > 1) hexdump8_ex(ent, DIR_ENTRY_LENGTH, 0);
|
||||
|
||||
// fill in an entry here
|
||||
memcpy(&ent[0], sfn, 11); // name
|
||||
ent[11] = (uint8_t)attr; // attribute
|
||||
ent[12] = 0; // reserved
|
||||
ent[13] = 0; // creation time tenth of second
|
||||
fat_write16(ent, 14, 0); // creation time seconds / 2
|
||||
fat_write16(ent, 16, 0); // creation date
|
||||
fat_write16(ent, 18, 0); // last accessed date
|
||||
fat_write16(ent, 20, starting_cluster >> 16); // fat cluster high
|
||||
fat_write16(ent, 22, 0); // modification time
|
||||
fat_write16(ent, 24, 0); // modification date
|
||||
fat_write16(ent, 26, starting_cluster); // fat cluster low
|
||||
fat_write32(ent, 28, size); // file size
|
||||
|
||||
LTRACEF_LEVEL(2, "filled in entry\n");
|
||||
if (LOCAL_TRACE > 1) hexdump8_ex(ent, DIR_ENTRY_LENGTH, 0);
|
||||
|
||||
// flush the data and exit
|
||||
dbi.mark_bcache_dirty();
|
||||
|
||||
// flush it
|
||||
bcache_flush(fat->bcache());
|
||||
|
||||
// fill in our location data and exit
|
||||
if (loc) {
|
||||
loc->starting_dir_cluster = starting_dir_cluster;
|
||||
loc->dir_offset = dir_offset;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
dir_offset += DIR_ENTRY_LENGTH;
|
||||
sector_offset += DIR_ENTRY_LENGTH;
|
||||
}
|
||||
|
||||
// move to the next sector
|
||||
err = dbi.next_sector();
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
// starting over at offset 0 in the new sector
|
||||
sector_offset = 0;
|
||||
}
|
||||
|
||||
// TODO: we probably ran out of space, add another cluster to the dir and start over
|
||||
|
||||
return ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
status_t fat_dir::opendir_priv(const dir_entry &entry, const dir_entry_location &loc, fat_dir_cookie **out_cookie) {
|
||||
// fill in our file info based on the entry
|
||||
start_cluster_ = entry.start_cluster;
|
||||
@@ -376,7 +606,7 @@ status_t fat_dir::opendir(fscookie *cookie, const char *name, dircookie **dcooki
|
||||
loc.starting_dir_cluster = 1;
|
||||
loc.dir_offset = 0;
|
||||
} else {
|
||||
status_t err = fat_walk(fat, name, &entry, &loc);
|
||||
status_t err = fat_dir_walk(fat, name, &entry, &loc);
|
||||
if (err != NO_ERROR) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ private:
|
||||
};
|
||||
|
||||
enum class fat_attribute : uint8_t {
|
||||
file = 0x0, // lack of attribute is a file
|
||||
read_only = 0x01,
|
||||
hidden = 0x02,
|
||||
system = 0x04,
|
||||
@@ -87,6 +88,15 @@ inline uint32_t fat_read32(const void *_buffer, size_t offset) {
|
||||
(buffer[offset + 3] << 24);
|
||||
}
|
||||
|
||||
inline void fat_write32(void *_buffer, size_t offset, uint32_t val) {
|
||||
auto *buffer = (uint8_t *)_buffer;
|
||||
|
||||
buffer[offset] = val;
|
||||
buffer[offset + 1] = val >> 8;
|
||||
buffer[offset + 2] = val >> 16;
|
||||
buffer[offset + 3] = val >> 24;
|
||||
}
|
||||
|
||||
inline uint16_t fat_read16(const void *_buffer, size_t offset) {
|
||||
auto *buffer = (const uint8_t *)_buffer;
|
||||
|
||||
@@ -94,6 +104,13 @@ inline uint16_t fat_read16(const void *_buffer, size_t offset) {
|
||||
(buffer[offset + 1] << 8);
|
||||
}
|
||||
|
||||
inline void fat_write16(void *_buffer, size_t offset, uint16_t val) {
|
||||
auto *buffer = (uint8_t *)_buffer;
|
||||
|
||||
buffer[offset] = val;
|
||||
buffer[offset + 1] = val >> 8;
|
||||
}
|
||||
|
||||
// In fat32, clusters between 0x0fff.fff8 and 0x0fff.ffff are interpreted as
|
||||
// end of file.
|
||||
const uint32_t EOF_CLUSTER_BASE = 0x0ffffff8;
|
||||
|
||||
@@ -47,4 +47,9 @@ inline bool operator==(const dir_entry_location &a, const dir_entry_location &b)
|
||||
return (a.starting_dir_cluster == b.starting_dir_cluster && a.dir_offset == b.dir_offset);
|
||||
}
|
||||
|
||||
status_t fat_walk(fat_fs *fat, const char *path, dir_entry *out_entry, dir_entry_location *loc);
|
||||
// walk a path, returning the entry and the location where it was found
|
||||
status_t fat_dir_walk(fat_fs *fat, const char *path, dir_entry *out_entry, dir_entry_location *loc);
|
||||
|
||||
// walk a path, allocating a new entry with the path name.
|
||||
// returns the dir entry location
|
||||
status_t fat_dir_allocate(fat_fs *fat, const char *path, fat_attribute attr, uint32_t starting_cluster, uint32_t size, dir_entry_location *loc);
|
||||
|
||||
@@ -78,6 +78,7 @@ status_t fat_file::open_file_priv(const dir_entry &entry, const dir_entry_locati
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
status_t fat_file::open_file(fscookie *cookie, const char *path, filecookie **fcookie) {
|
||||
fat_fs *fs = (fat_fs *)cookie;
|
||||
|
||||
@@ -88,7 +89,7 @@ status_t fat_file::open_file(fscookie *cookie, const char *path, filecookie **fc
|
||||
// look for the file in the fs
|
||||
dir_entry entry;
|
||||
dir_entry_location loc;
|
||||
status_t err = fat_walk(fs, path, &entry, &loc);
|
||||
status_t err = fat_dir_walk(fs, path, &entry, &loc);
|
||||
if (err != NO_ERROR) {
|
||||
return err;
|
||||
}
|
||||
@@ -204,6 +205,7 @@ ssize_t fat_file::read_file_priv(void *_buf, const off_t offset, size_t len) {
|
||||
return amount_read;
|
||||
}
|
||||
|
||||
// static
|
||||
ssize_t fat_file::read_file(filecookie *fcookie, void *_buf, const off_t offset, size_t len) {
|
||||
fat_file *file = (fat_file *)fcookie;
|
||||
|
||||
@@ -213,11 +215,14 @@ ssize_t fat_file::read_file(filecookie *fcookie, void *_buf, const off_t offset,
|
||||
status_t fat_file::stat_file_priv(struct file_stat *stat) {
|
||||
AutoLock guard(fs_->lock);
|
||||
|
||||
LTRACEF("file %p state %p\n", this, stat);
|
||||
|
||||
stat->size = length_;
|
||||
stat->is_dir = is_dir();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// static
|
||||
status_t fat_file::stat_file(filecookie *fcookie, struct file_stat *stat) {
|
||||
fat_file *file = (fat_file *)fcookie;
|
||||
|
||||
@@ -234,6 +239,7 @@ status_t fat_file::close_file_priv(bool *last_ref) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// static
|
||||
status_t fat_file::close_file(filecookie *fcookie) {
|
||||
fat_file *file = (fat_file *)fcookie;
|
||||
|
||||
@@ -251,3 +257,35 @@ status_t fat_file::close_file(filecookie *fcookie) {
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// static
|
||||
status_t fat_file::create_file(fscookie *cookie, const char *path, filecookie **fcookie, uint64_t len) {
|
||||
fat_fs *fs = (fat_fs *)cookie;
|
||||
|
||||
LTRACEF("fs %p path '%s' len %" PRIu64 "\n", fs, path, len);
|
||||
|
||||
// currently only support zero length files
|
||||
if (len != 0) {
|
||||
return ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
{
|
||||
AutoLock guard(fs->lock);
|
||||
|
||||
// tell the dir code to find us a spot
|
||||
dir_entry_location loc;
|
||||
status_t err = fat_dir_allocate(fs, path, fat_attribute::file, 0, 0, &loc);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// we have found and allocated a spot
|
||||
fat_file *file = new fat_file(fs);
|
||||
file->dir_loc_ = loc;
|
||||
file->inc_ref();
|
||||
*fcookie = (filecookie *)file;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
static ssize_t read_file(filecookie *fcookie, void *_buf, const off_t offset, size_t len);
|
||||
static status_t stat_file(filecookie *fcookie, struct file_stat *stat);
|
||||
static status_t close_file(filecookie *fcookie);
|
||||
static status_t create_file(fscookie *cookie, const char *path, filecookie **fcookie, uint64_t len);
|
||||
|
||||
// used by fs node list maintenance
|
||||
// node in the fs's list of open files and dirs
|
||||
@@ -48,7 +49,7 @@ protected:
|
||||
|
||||
fat_fs *fs_ = nullptr; // pointer back to the fs instance we're in
|
||||
|
||||
// pointer to our dir entry, acts as our unique key
|
||||
// pointer to our dir entry, acts as our unique key in the fs list
|
||||
dir_entry_location dir_loc_ {};
|
||||
|
||||
// our start cluster and length
|
||||
|
||||
@@ -107,3 +107,11 @@ status_t file_block_iterator::load_bcache_block(bnum_t bnum) {
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t file_block_iterator::mark_bcache_dirty() {
|
||||
if (bcache_buf) {
|
||||
return bcache_mark_block_dirty(fat->bcache(), bcache_bnum);
|
||||
} else {
|
||||
return ERR_NO_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,21 @@ public:
|
||||
|
||||
DISALLOW_COPY_ASSIGN_AND_MOVE(file_block_iterator);
|
||||
|
||||
const uint8_t *get_bcache_ptr(size_t offset) {
|
||||
const uint8_t *get_bcache_ptr(size_t offset) const {
|
||||
DEBUG_ASSERT(offset < fat->info().bytes_per_sector);
|
||||
DEBUG_ASSERT(bcache_buf);
|
||||
return (const uint8_t *)bcache_buf + offset;
|
||||
}
|
||||
|
||||
uint8_t *get_bcache_ptr(size_t offset) {
|
||||
DEBUG_ASSERT(offset < fat->info().bytes_per_sector);
|
||||
DEBUG_ASSERT(bcache_buf);
|
||||
return (uint8_t *)bcache_buf + offset;
|
||||
}
|
||||
|
||||
// write mark the current block as modified
|
||||
status_t mark_bcache_dirty();
|
||||
|
||||
// move N sectors ahead in the file, walking the FAT cluster chain as necessary.
|
||||
// sectors == 0 will ensure the current block is loaded.
|
||||
status_t next_sectors(uint32_t sectors);
|
||||
|
||||
@@ -46,6 +46,29 @@ __NO_INLINE static void fat_dump(fat_fs *fat) {
|
||||
fat_fs::fat_fs() = default;
|
||||
fat_fs::~fat_fs() = default;
|
||||
|
||||
void fat_fs::add_to_file_list(fat_file *file) {
|
||||
DEBUG_ASSERT(lock.is_held());
|
||||
DEBUG_ASSERT(!list_in_list(&file->node_));
|
||||
|
||||
LTRACEF("file %p, location %u:%u\n", file, file->dir_loc().starting_dir_cluster, file->dir_loc().dir_offset);
|
||||
|
||||
list_add_head(&file_list_, &file->node_);
|
||||
}
|
||||
|
||||
fat_file *fat_fs::lookup_file(const dir_entry_location &loc) {
|
||||
DEBUG_ASSERT(lock.is_held());
|
||||
|
||||
fat_file *f;
|
||||
list_for_every_entry(&file_list_, f, fat_file, node_) {
|
||||
if (loc == f->dir_loc()) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static fs hooks
|
||||
status_t fat_fs::mount(bdev_t *dev, fscookie **cookie) {
|
||||
status_t result = NO_ERROR;
|
||||
|
||||
@@ -210,6 +233,7 @@ status_t fat_fs::mount(bdev_t *dev, fscookie **cookie) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
status_t fat_fs::unmount(fscookie *cookie) {
|
||||
auto *fat = (fat_fs *)cookie;
|
||||
|
||||
@@ -227,28 +251,6 @@ status_t fat_fs::unmount(fscookie *cookie) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void fat_fs::add_to_file_list(fat_file *file) {
|
||||
DEBUG_ASSERT(lock.is_held());
|
||||
DEBUG_ASSERT(!list_in_list(&file->node_));
|
||||
|
||||
LTRACEF("file %p, location %u:%u\n", file, file->dir_loc().starting_dir_cluster, file->dir_loc().dir_offset);
|
||||
|
||||
list_add_head(&file_list_, &file->node_);
|
||||
}
|
||||
|
||||
fat_file *fat_fs::lookup_file(const dir_entry_location &loc) {
|
||||
DEBUG_ASSERT(lock.is_held());
|
||||
|
||||
fat_file *f;
|
||||
list_for_every_entry(&file_list_, f, fat_file, node_) {
|
||||
if (loc == f->dir_loc()) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const struct fs_api fat_api = {
|
||||
.format = nullptr,
|
||||
.fs_stat = nullptr,
|
||||
@@ -256,7 +258,7 @@ static const struct fs_api fat_api = {
|
||||
.mount = fat_fs::mount,
|
||||
.unmount = fat_fs::unmount,
|
||||
.open = fat_file::open_file,
|
||||
.create = nullptr,
|
||||
.create = fat_file::create_file,
|
||||
.remove = nullptr,
|
||||
.truncate = nullptr,
|
||||
.stat = fat_file::stat_file,
|
||||
|
||||
Reference in New Issue
Block a user