decreased the code size to less than 5000 bytes. (msp430 code)

improved clarity in read and write code.
added negative offset check in cfs_seek().
removed unnecessary multiplication.
This commit is contained in:
nvt-se 2009-05-13 13:27:19 +00:00
parent bc6c9410cc
commit 2978270e43

View file

@ -81,6 +81,8 @@
#define FD_APPENDABLE(fd) (coffee_fd_set[(fd)].flags & CFS_APPEND) #define FD_APPENDABLE(fd) (coffee_fd_set[(fd)].flags & CFS_APPEND)
#define FILE_MODIFIED(file) ((file)->flags & COFFEE_FILE_MODIFIED) #define FILE_MODIFIED(file) ((file)->flags & COFFEE_FILE_MODIFIED)
#define FILE_FREE(file) ((file)->max_pages == 0)
#define FILE_UNREFERENCED(file) ((file)->references == 0)
/* File header flags. */ /* File header flags. */
#define HDR_FLAG_VALID 0x1 /* Completely written header. */ #define HDR_FLAG_VALID 0x1 /* Completely written header. */
@ -333,10 +335,10 @@ load_file(coffee_page_t start, struct file_header *hdr)
* value INVALID_PAGE. * value INVALID_PAGE.
*/ */
for(i = 0, unreferenced = free = -1; i < COFFEE_MAX_OPEN_FILES; i++) { for(i = 0, unreferenced = free = -1; i < COFFEE_MAX_OPEN_FILES; i++) {
if(coffee_files[i].page == INVALID_PAGE) { if(FILE_FREE(&coffee_files[i])) {
free = i; free = i;
break; break;
} else if(coffee_files[i].references == 0) { } else if(FILE_UNREFERENCED(&coffee_files[i])) {
unreferenced = i; unreferenced = i;
} }
} }
@ -371,7 +373,7 @@ find_file(const char *name)
/* First check if the file metadata is cached. */ /* First check if the file metadata is cached. */
for(i = 0; i < COFFEE_MAX_OPEN_FILES; i++) { for(i = 0; i < COFFEE_MAX_OPEN_FILES; i++) {
if(coffee_files[i].max_pages == 0) { if(FILE_FREE(&coffee_files[i])) {
continue; continue;
} }
@ -469,7 +471,7 @@ remove_by_page(coffee_page_t page, int remove_log, int close_fds)
} }
if(remove_log && HDR_MODIFIED(hdr)) { if(remove_log && HDR_MODIFIED(hdr)) {
if (remove_by_page(hdr.log_page, 0, 0) < 0) { if(remove_by_page(hdr.log_page, 0, 0) < 0) {
return -1; return -1;
} }
} }
@ -512,7 +514,8 @@ page_count(cfs_offset_t size)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static struct file * static struct file *
reserve(const char *name, coffee_page_t pages, int allow_duplicates) reserve(const char *name, coffee_page_t pages,
int allow_duplicates, unsigned flags)
{ {
struct file_header hdr; struct file_header hdr;
coffee_page_t page; coffee_page_t page;
@ -543,7 +546,7 @@ reserve(const char *name, coffee_page_t pages, int allow_duplicates)
memcpy(hdr.name, name, sizeof(hdr.name) - 1); memcpy(hdr.name, name, sizeof(hdr.name) - 1);
hdr.name[sizeof(hdr.name) - 1] = '\0'; hdr.name[sizeof(hdr.name) - 1] = '\0';
hdr.max_pages = pages; hdr.max_pages = pages;
hdr.flags = HDR_FLAG_ALLOCATED; hdr.flags = HDR_FLAG_ALLOCATED | flags;
write_header(&hdr, page); write_header(&hdr, page);
PRINTF("Coffee: Reserved %u pages starting from %u for file %s\n", PRINTF("Coffee: Reserved %u pages starting from %u for file %s\n",
@ -561,9 +564,9 @@ adjust_log_config(struct file_header *hdr,
uint16_t *log_record_size, uint16_t *log_records) uint16_t *log_record_size, uint16_t *log_records)
{ {
*log_record_size = hdr->log_record_size == 0 ? *log_record_size = hdr->log_record_size == 0 ?
COFFEE_PAGE_SIZE : hdr->log_record_size; COFFEE_PAGE_SIZE : hdr->log_record_size;
*log_records = hdr->log_records == 0 ? *log_records = hdr->log_records == 0 ?
COFFEE_LOG_SIZE / *log_record_size : hdr->log_records; COFFEE_LOG_SIZE / *log_record_size : hdr->log_records;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static uint16_t static uint16_t
@ -660,7 +663,7 @@ create_log(struct file *file, struct file_header *hdr)
size = log_records * sizeof(uint16_t); /* Log index size. */ size = log_records * sizeof(uint16_t); /* Log index size. */
size += log_records * log_record_size; /* Log data size. */ size += log_records * log_record_size; /* Log data size. */
log_file = reserve(hdr->name, page_count(size), 1); log_file = reserve(hdr->name, page_count(size), 1, HDR_FLAG_LOG);
if(log_file == NULL) { if(log_file == NULL) {
return INVALID_PAGE; return INVALID_PAGE;
} }
@ -669,9 +672,6 @@ create_log(struct file *file, struct file_header *hdr)
hdr->flags |= HDR_FLAG_MODIFIED; hdr->flags |= HDR_FLAG_MODIFIED;
hdr->log_page = log_page; hdr->log_page = log_page;
write_header(hdr, file->page); write_header(hdr, file->page);
read_header(hdr, log_page);
hdr->flags |= HDR_FLAG_LOG;
write_header(hdr, log_page);
file->flags |= COFFEE_FILE_MODIFIED; file->flags |= COFFEE_FILE_MODIFIED;
return log_page; return log_page;
@ -701,7 +701,7 @@ merge_log(coffee_page_t file_page, int extend)
* already been calculated with in the previous reservation. * already been calculated with in the previous reservation.
*/ */
max_pages = hdr.max_pages << extend; max_pages = hdr.max_pages << extend;
new_file = reserve(hdr.name, max_pages, 1); new_file = reserve(hdr.name, max_pages, 1, 0);
if(new_file == NULL) { if(new_file == NULL) {
cfs_close(fd); cfs_close(fd);
return -1; return -1;
@ -796,7 +796,7 @@ write_log_page(struct file *file, struct log_param *lp)
int16_t log_record; int16_t log_record;
uint16_t log_record_size; uint16_t log_record_size;
uint16_t log_records; uint16_t log_records;
cfs_offset_t table_base, record_base; cfs_offset_t offset;
struct log_param lp_out; struct log_param lp_out;
read_header(&hdr, file->page); read_header(&hdr, file->page);
@ -829,26 +829,26 @@ write_log_page(struct file *file, struct log_param *lp)
{ {
unsigned char copy_buf[log_record_size]; unsigned char copy_buf[log_record_size];
lp_out.offset = region * log_record_size; lp_out.offset = offset = region * log_record_size;
lp_out.buf = copy_buf; lp_out.buf = copy_buf;
lp_out.size = log_record_size; lp_out.size = log_record_size;
if((lp->offset > 0 || lp->size != log_record_size) && if((lp->offset > 0 || lp->size != log_record_size) &&
read_log_page(&hdr, log_record, &lp_out) < 0) { read_log_page(&hdr, log_record, &lp_out) < 0) {
COFFEE_READ(copy_buf, sizeof(copy_buf), COFFEE_READ(copy_buf, sizeof(copy_buf),
absolute_offset(file->page, region * log_record_size)); absolute_offset(file->page, offset));
} }
memcpy((char *) &copy_buf + lp->offset, lp->buf, lp->size); memcpy((char *) &copy_buf + lp->offset, lp->buf, lp->size);
table_base = absolute_offset(log_page, 0); offset = absolute_offset(log_page, 0);
++region; ++region;
COFFEE_WRITE(&region, sizeof(region), COFFEE_WRITE(&region, sizeof(region),
table_base + log_record * sizeof(region)); offset + log_record * sizeof(region));
record_base = table_base + log_records * sizeof(region); offset += log_records * sizeof(region);
COFFEE_WRITE(copy_buf, sizeof(copy_buf), COFFEE_WRITE(copy_buf, sizeof(copy_buf),
record_base + log_record * log_record_size); offset + log_record * log_record_size);
file->next_log_record = log_record + 1; file->next_log_record = log_record + 1;
} }
@ -888,7 +888,7 @@ cfs_open(const char *name, int flags)
if((flags & (CFS_READ | CFS_WRITE)) == CFS_READ) { if((flags & (CFS_READ | CFS_WRITE)) == CFS_READ) {
return -1; return -1;
} }
fdp->file = reserve(name, page_count(COFFEE_DYN_SIZE), 1); fdp->file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);
if(fdp->file == NULL) { if(fdp->file == NULL) {
return -1; return -1;
} }
@ -917,20 +917,12 @@ cfs_close(int fd)
cfs_offset_t cfs_offset_t
cfs_seek(int fd, cfs_offset_t offset, int whence) cfs_seek(int fd, cfs_offset_t offset, int whence)
{ {
struct file_header hdr;
struct file_desc *fdp; struct file_desc *fdp;
if(!FD_VALID(fd)) { if(!FD_VALID(fd)) {
return -1; return -1;
} }
fdp = &coffee_fd_set[fd]; fdp = &coffee_fd_set[fd];
read_header(&hdr, fdp->file->page);
/* Check if the offset is within the file boundary. */
if(sizeof(hdr) + offset >= hdr.max_pages * COFFEE_PAGE_SIZE ||
sizeof(hdr) + offset < offset) {
return -1;
}
if(whence == CFS_SEEK_SET) { if(whence == CFS_SEEK_SET) {
fdp->offset = offset; fdp->offset = offset;
@ -942,6 +934,11 @@ cfs_seek(int fd, cfs_offset_t offset, int whence)
return (cfs_offset_t)-1; return (cfs_offset_t)-1;
} }
if(fdp->offset < 0 || fdp->offset > fdp->file->max_pages * COFFEE_PAGE_SIZE) {
fdp->offset = 0;
return -1;
}
if(fdp->file->end < fdp->offset) { if(fdp->file->end < fdp->offset) {
fdp->file->end = fdp->offset; fdp->file->end = fdp->offset;
} }
@ -974,9 +971,8 @@ cfs_read(int fd, void *buf, unsigned size)
struct file_header hdr; struct file_header hdr;
struct file_desc *fdp; struct file_desc *fdp;
struct file *file; struct file *file;
unsigned remains, read_chunk; unsigned bytes_left;
int r; int r;
cfs_offset_t base, offset;
struct log_param lp; struct log_param lp;
if(!(FD_VALID(fd) && FD_READABLE(fd))) { if(!(FD_VALID(fd) && FD_READABLE(fd))) {
@ -989,41 +985,34 @@ cfs_read(int fd, void *buf, unsigned size)
size = file->end - fdp->offset; size = file->end - fdp->offset;
} }
read_chunk = COFFEE_PAGE_SIZE; bytes_left = size;
if(FILE_MODIFIED(file)) { if(FILE_MODIFIED(file)) {
read_header(&hdr, file->page); read_header(&hdr, file->page);
if(hdr.log_record_size > 0) {
read_chunk = hdr.log_record_size;
}
} }
remains = size;
base = fdp->offset;
offset = 0;
/* /*
* Fill the buffer by copying from the log in first hand, or the * Fill the buffer by copying from the log in first hand, or the
* ordinary file if the page has no log record. * ordinary file if the page has no log record.
*/ */
while(remains) { while(bytes_left) {
watchdog_periodic(); watchdog_periodic();
r = -1; r = -1;
if(FILE_MODIFIED(file)) { if(FILE_MODIFIED(file)) {
lp.offset = base + offset; lp.offset = fdp->offset;
lp.buf = (char *)buf + offset; lp.buf = buf;
lp.size = remains; lp.size = bytes_left;
r = read_log_page(&hdr, file->next_log_record, &lp); r = read_log_page(&hdr, file->next_log_record, &lp);
} }
/* Read from the original file if we cannot find the data in the log. */ /* Read from the original file if we cannot find the data in the log. */
if(r < 0) { if(r < 0) {
r = remains > read_chunk ? read_chunk : remains; r = bytes_left;
COFFEE_READ((char *) buf + offset, r, COFFEE_READ(buf, r, absolute_offset(file->page, fdp->offset));
absolute_offset(file->page, base + offset));
} }
remains -= r; bytes_left -= r;
offset += r; fdp->offset += r;
buf += r;
} }
fdp->offset += offset; return size;
return offset;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
int int
@ -1033,7 +1022,7 @@ cfs_write(int fd, const void *buf, unsigned size)
struct file *file; struct file *file;
int i; int i;
struct log_param lp; struct log_param lp;
cfs_offset_t remains; cfs_offset_t bytes_left;
if(!(FD_VALID(fd) && FD_WRITABLE(fd))) { if(!(FD_VALID(fd) && FD_WRITABLE(fd))) {
return -1; return -1;
@ -1053,26 +1042,32 @@ cfs_write(int fd, const void *buf, unsigned size)
} }
if(FILE_MODIFIED(file) || fdp->offset < file->end) { if(FILE_MODIFIED(file) || fdp->offset < file->end) {
remains = size; bytes_left = size;
while(remains) { while(bytes_left) {
lp.offset = fdp->offset; lp.offset = fdp->offset;
lp.buf = (char *)buf + size - remains; lp.buf = buf;
lp.size = remains; lp.size = bytes_left;
i = write_log_page(file, &lp); i = write_log_page(file, &lp);
if(i == 0) {
file = fdp->file;
/* The file was merged with the log. Try again. */
continue;
}
if(i < 0) { if(i < 0) {
return size - remains > 0 ? size - remains : -1; /* Return -1 if we wrote nothing because the log write failed. */
if(size == bytes_left) {
return -1;
}
break;
} else if(i == 0) {
/* The file was merged with the log. */
file = fdp->file;
} else {
/* A log record was written. */
bytes_left -= i;
fdp->offset += i;
buf += i;
} }
remains -= i;
fdp->offset += i;
} }
if(fdp->offset > file->end) { if(fdp->offset > file->end) {
/* Update the original file's end with a dummy write. */ /* Update the original file's end with a dummy write. */
*(char *)buf = 0xff;
COFFEE_WRITE(buf, 1, absolute_offset(file->page, fdp->offset)); COFFEE_WRITE(buf, 1, absolute_offset(file->page, fdp->offset));
} }
} else { } else {
@ -1129,7 +1124,7 @@ cfs_closedir(struct cfs_dir *dir)
int int
cfs_coffee_reserve(const char *name, cfs_offset_t size) cfs_coffee_reserve(const char *name, cfs_offset_t size)
{ {
return reserve(name, page_count(size), 0) == NULL ? -1 : 0; return reserve(name, page_count(size), 0, 0) == NULL ? -1 : 0;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
int int