00001
00040 #include "battfs.h"
00041 #include "cfg/cfg_battfs.h"
00042 #include <cfg/debug.h>
00043 #include <cfg/macros.h>
00044 #include <cfg/test.h>
00045 #include <cpu/byteorder.h>
00046
00047 #define LOG_LEVEL BATTFS_LOG_LEVEL
00048 #define LOG_FORMAT BATTFS_LOG_FORMAT
00049 #include <cfg/log.h>
00050
00051 #include <string.h>
00052
00053 #if LOG_LEVEL >= LOG_LVL_INFO
00054 static void dumpPageArray(struct BattFsSuper *disk)
00055 {
00056 kprintf("Page array dump, free_page_start %d:", disk->free_page_start);
00057 for (pgcnt_t i = 0; i < disk->dev->blk_cnt; i++)
00058 {
00059 if (!(i % 16))
00060 kputchar('\n');
00061 kprintf("%04d ", disk->page_array[i]);
00062 }
00063 kputchar('\n');
00064 }
00065 #endif
00066
00071 INLINE void battfs_to_disk(struct BattFsPageHeader *hdr, uint8_t *buf)
00072 {
00073 STATIC_ASSERT(BATTFS_HEADER_LEN == 12);
00074 buf[0] = hdr->inode;
00075
00076 buf[1] = hdr->fill;
00077 buf[2] = hdr->fill >> 8;
00078
00079 buf[3] = hdr->pgoff;
00080 buf[4] = hdr->pgoff >> 8;
00081
00082
00083
00084
00085
00086 buf[5] = hdr->seq;
00087 buf[6] = hdr->seq >> 8;
00088 buf[7] = hdr->seq >> 16;
00089 buf[8] = hdr->seq >> 24;
00090 buf[9] = hdr->seq >> 32;
00091
00092
00093
00094
00095
00096
00097 buf[10] = hdr->fcs;
00098 buf[11] = hdr->fcs >> 8;
00099 }
00100
00105 INLINE void disk_to_battfs(uint8_t *buf, struct BattFsPageHeader *hdr)
00106 {
00107 STATIC_ASSERT(BATTFS_HEADER_LEN == 12);
00108 hdr->inode = buf[0];
00109 hdr->fill = buf[2] << 8 | buf[1];
00110 hdr->pgoff = buf[4] << 8 | buf[3];
00111 hdr->seq = (seq_t)buf[9] << 32 | (seq_t)buf[8] << 24 | (seq_t)buf[7] << 16 | buf[6] << 8 | buf[5];
00112 hdr->fcs = buf[11] << 8 | buf[10];
00113 }
00114
00118 static fcs_t computeFcs(struct BattFsPageHeader *hdr)
00119 {
00120 uint8_t buf[BATTFS_HEADER_LEN];
00121 fcs_t cks;
00122
00123 battfs_to_disk(hdr, buf);
00124 rotating_init(&cks);
00125
00126 rotating_update(buf, BATTFS_HEADER_LEN - sizeof(fcs_t), &cks);
00127 return cks;
00128 }
00129
00134 static bool readHdr(struct BattFsSuper *disk, pgcnt_t page, struct BattFsPageHeader *hdr)
00135 {
00136 uint8_t buf[BATTFS_HEADER_LEN];
00137
00138
00139
00140
00141
00142
00143 if (kblock_read(disk->dev, page, buf, disk->data_size, BATTFS_HEADER_LEN)
00144 != BATTFS_HEADER_LEN)
00145 {
00146 LOG_ERR("page[%d]\n", page);
00147 return false;
00148 }
00149
00150
00151 disk_to_battfs(buf, hdr);
00152
00153 return true;
00154 }
00155
00156 static bool writeHdr(struct BattFsSuper *disk, pgcnt_t page, struct BattFsPageHeader *hdr)
00157 {
00158 uint8_t buf[BATTFS_HEADER_LEN];
00159
00160 #warning FIXME:refactor computeFcs to save time and stack
00161 hdr->fcs = computeFcs(hdr);
00162
00163 battfs_to_disk(hdr, buf);
00164
00165
00166
00167
00168
00169
00170 if (kblock_write(disk->dev, page, buf, disk->data_size, BATTFS_HEADER_LEN)
00171 != BATTFS_HEADER_LEN)
00172 {
00173 LOG_ERR("writing to buffer\n");
00174 return false;
00175 }
00176 return true;
00177 }
00178
00179
00184 static pgcnt_t countPages(pgoff_t *filelen_table, inode_t inode)
00185 {
00186 pgcnt_t cnt = 0;
00187
00188 for (inode_t i = 0; i < inode; i++)
00189 cnt += filelen_table[i];
00190
00191 return cnt;
00192 }
00193
00198 static void movePages(struct BattFsSuper *disk, pgcnt_t src, int offset)
00199 {
00200 pgcnt_t dst = src + offset;
00201 LOG_INFO("src %d, offset %d, size %d\n", src, offset, (unsigned int)((disk->dev->blk_cnt - MAX(dst, src)) * sizeof(pgcnt_t)));
00202 memmove(&disk->page_array[dst], &disk->page_array[src], (disk->dev->blk_cnt - MAX(dst, src)) * sizeof(pgcnt_t));
00203
00204 if (offset < 0)
00205 {
00206
00207 for (pgcnt_t page = disk->dev->blk_cnt + offset; page < disk->dev->blk_cnt; page++)
00208 disk->page_array[page] = PAGE_UNSET_SENTINEL;
00209 }
00210 }
00211
00221 static bool countDiskFilePages(struct BattFsSuper *disk, pgoff_t *filelen_table)
00222 {
00223 BattFsPageHeader hdr;
00224 disk->free_page_start = 0;
00225
00226
00227 for (pgcnt_t page = 0; page < disk->dev->blk_cnt; page++)
00228 {
00229 if (!readHdr(disk, page, &hdr))
00230 return false;
00231
00232
00233 disk->free_bytes += disk->data_size;
00234
00235
00236 if (hdr.fcs == computeFcs(&hdr))
00237 {
00238 ASSERT(hdr.fill <= disk->data_size);
00239
00240
00241 filelen_table[hdr.inode]++;
00242
00243
00244 disk->free_bytes -= hdr.fill;
00245 disk->free_page_start++;
00246 }
00247 }
00248 LOG_INFO("free_bytes:%ld, free_page_start:%d\n", (long)disk->free_bytes, disk->free_page_start);
00249
00250 return true;
00251 }
00252
00267 static bool fillPageArray(struct BattFsSuper *disk, pgoff_t *filelen_table)
00268 {
00269 BattFsPageHeader hdr;
00270 pgcnt_t curr_free_page = disk->free_page_start;
00271
00272 for (pgcnt_t page = 0; page < disk->dev->blk_cnt; page++)
00273 {
00274 if (!readHdr(disk, page, &hdr))
00275 return false;
00276
00277
00278 if (hdr.fcs == computeFcs(&hdr))
00279 {
00280
00281 pgcnt_t array_pos = countPages(filelen_table, hdr.inode);
00282 array_pos += hdr.pgoff;
00283
00284
00285
00286 if (disk->page_array[array_pos] == PAGE_UNSET_SENTINEL)
00287 disk->page_array[array_pos] = page;
00288 else
00289 {
00290 BattFsPageHeader hdr_prv;
00291
00292 if (!readHdr(disk, disk->page_array[array_pos], &hdr_prv))
00293 return false;
00294
00295
00296 ASSERT(hdr_prv.fcs == computeFcs(&hdr_prv));
00297
00298
00299 ASSERT(hdr.inode == hdr_prv.inode);
00300 ASSERT(hdr.pgoff == hdr_prv.pgoff);
00301 ASSERT(hdr.seq != hdr_prv.seq);
00302
00303 pgcnt_t new_page, old_page;
00304 fill_t old_fill;
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 if (hdr.seq > hdr_prv.seq)
00315 {
00316
00317 old_page = disk->page_array[array_pos];
00318 new_page = page;
00319 old_fill = hdr_prv.fill;
00320 }
00321 else
00322 {
00323
00324 old_page = page;
00325 new_page = disk->page_array[array_pos];
00326 old_fill = hdr.fill;
00327 }
00328
00329
00330 disk->page_array[array_pos] = new_page;
00331
00332 disk->free_bytes += old_fill;
00333
00334 array_pos -= hdr.pgoff;
00335 array_pos += filelen_table[hdr.inode];
00336 movePages(disk, array_pos, -1);
00337
00338 filelen_table[hdr.inode]--;
00339 disk->free_page_start--;
00340 curr_free_page--;
00341
00342 ASSERT(disk->page_array[curr_free_page] == PAGE_UNSET_SENTINEL);
00343 disk->page_array[curr_free_page++] = old_page;
00344
00345 }
00346 }
00347 else
00348 {
00349
00350 ASSERT(disk->page_array[curr_free_page] == PAGE_UNSET_SENTINEL);
00351
00352 disk->page_array[curr_free_page++] = page;
00353 }
00354 }
00355 return true;
00356 }
00357
00358
00364 bool battfs_mount(struct BattFsSuper *disk, struct KBlock *dev, pgcnt_t *page_array, size_t array_size)
00365 {
00366 pgoff_t filelen_table[BATTFS_MAX_FILES];
00367
00368 ASSERT(dev);
00369 ASSERT(kblock_partialWrite(dev));
00370 disk->dev = dev;
00371
00372 ASSERT(disk->dev->blk_size > BATTFS_HEADER_LEN);
00373
00374 disk->data_size = disk->dev->blk_size - BATTFS_HEADER_LEN;
00375 ASSERT(disk->dev->blk_cnt);
00376 ASSERT(disk->dev->blk_cnt < PAGE_UNSET_SENTINEL - 1);
00377 ASSERT(page_array);
00378 disk->page_array = page_array;
00379 ASSERT(array_size >= disk->dev->blk_cnt * sizeof(pgcnt_t));
00380
00381 memset(filelen_table, 0, BATTFS_MAX_FILES * sizeof(pgoff_t));
00382
00383 disk->free_bytes = 0;
00384 disk->disk_size = (disk_size_t)disk->data_size * disk->dev->blk_cnt;
00385
00386
00387 if (!countDiskFilePages(disk, filelen_table))
00388 {
00389 LOG_ERR("counting file pages\n");
00390 return false;
00391 }
00392
00393
00394
00395
00396 for (pgcnt_t page = 0; page < disk->dev->blk_cnt; page++)
00397 disk->page_array[page] = PAGE_UNSET_SENTINEL;
00398
00399
00400 if (!fillPageArray(disk, filelen_table))
00401 {
00402 LOG_ERR("filling page array\n");
00403 return false;
00404 }
00405 #if LOG_LEVEL >= LOG_LVL_INFO
00406 dumpPageArray(disk);
00407 #endif
00408 #if CONFIG_BATTFS_SHUFFLE_FREE_PAGES
00409 SHUFFLE(&disk->page_array[disk->free_page_start], disk->dev->blk_cnt - disk->free_page_start);
00410
00411 LOG_INFO("Page array after shuffle:\n");
00412 #if LOG_LEVEL >= LOG_LVL_INFO
00413 dumpPageArray(disk);
00414 #endif
00415 #endif
00416
00417 LIST_INIT(&disk->file_opened_list);
00418 return true;
00419 }
00420
00425 bool battfs_fsck(struct BattFsSuper *disk)
00426 {
00427 #define FSCHECK(cond) do { if(!(cond)) { LOG_ERR("\"" #cond "\"\n"); return false; } } while (0)
00428
00429 FSCHECK(disk->free_page_start <= disk->dev->blk_cnt);
00430 FSCHECK(disk->data_size < disk->dev->blk_size);
00431 FSCHECK(disk->free_bytes <= disk->disk_size);
00432
00433 disk_size_t free_bytes = 0;
00434 BattFsPageHeader hdr, prev_hdr;
00435 inode_t files = 0;
00436 pgcnt_t page_used = 0;
00437
00438 bool start = true;
00439
00440
00441
00442 FSCHECK(readHdr(disk, 0, &prev_hdr));
00443 for (pgcnt_t page = 0; page < disk->dev->blk_cnt; page++)
00444 {
00445 FSCHECK(readHdr(disk, disk->page_array[page], &hdr));
00446 free_bytes += disk->data_size;
00447
00448 if (page < disk->free_page_start)
00449 {
00450 FSCHECK(computeFcs(&hdr) == hdr.fcs);
00451 page_used++;
00452 free_bytes -= hdr.fill;
00453 if (hdr.inode != prev_hdr.inode || start)
00454 {
00455 if (LIKELY(!start))
00456 FSCHECK(hdr.inode > prev_hdr.inode);
00457 else
00458 start = false;
00459
00460 FSCHECK(hdr.pgoff == 0);
00461 files++;
00462 }
00463 else
00464 {
00465 FSCHECK(hdr.fill != 0);
00466 FSCHECK(prev_hdr.fill == disk->data_size);
00467 FSCHECK(hdr.pgoff == prev_hdr.pgoff + 1);
00468 }
00469 prev_hdr = hdr;
00470 }
00471 }
00472
00473 FSCHECK(page_used == disk->free_page_start);
00474 FSCHECK(free_bytes == disk->free_bytes);
00475
00476 return true;
00477 }
00478
00483 static int battfs_flush(struct KFile *fd)
00484 {
00485 BattFs *fdb = BATTFS_CAST(fd);
00486
00487 if (kblock_flush(fdb->disk->dev) == 0)
00488 return 0;
00489 else
00490 {
00491 fdb->errors |= BATTFS_DISK_FLUSHBUF_ERR;
00492 return EOF;
00493 }
00494 }
00495
00500 static int battfs_fileclose(struct KFile *fd)
00501 {
00502 BattFs *fdb = BATTFS_CAST(fd);
00503
00504 if (battfs_flush(fd) == 0)
00505 {
00506 REMOVE(&fdb->link);
00507 return 0;
00508 }
00509 else
00510 return EOF;
00511 }
00512
00513 #define NO_SPACE PAGE_UNSET_SENTINEL
00514
00515 static pgcnt_t allocateNewPage(struct BattFsSuper *disk, pgcnt_t new_pos, inode_t inode)
00516 {
00517 if (SPACE_OVER(disk))
00518 {
00519 LOG_ERR("No disk space available!\n");
00520 return NO_SPACE;
00521 }
00522
00523 LOG_INFO("Getting new page %d, pos %d\n", disk->page_array[disk->free_page_start], new_pos);
00524 pgcnt_t new_page = disk->page_array[disk->free_page_start++];
00525 memmove(&disk->page_array[new_pos + 1], &disk->page_array[new_pos], (disk->free_page_start - new_pos - 1) * sizeof(pgcnt_t));
00526
00527 Node *n;
00528
00529 FOREACH_NODE(n, &disk->file_opened_list)
00530 {
00531 BattFs *file = containerof(n, BattFs, link);
00532 if (file->inode > inode)
00533 {
00534 LOG_INFO("Move file %d start pos\n", file->inode);
00535 file->start++;
00536 }
00537 }
00538
00539 disk->page_array[new_pos] = new_page;
00540 return new_page;
00541 }
00542
00543 static pgcnt_t renewPage(struct BattFsSuper *disk, pgcnt_t old_pos)
00544 {
00545 if (SPACE_OVER(disk))
00546 {
00547 LOG_ERR("No disk space available!\n");
00548 return NO_SPACE;
00549 }
00550
00551
00552 pgcnt_t new_page = disk->page_array[disk->free_page_start];
00553 movePages(disk, disk->free_page_start + 1, -1);
00554
00555
00556 LOG_INFO("Setting page %d as free\n", old_pos);
00557 disk->page_array[disk->dev->blk_cnt - 1] = old_pos;
00558 return new_page;
00559 }
00560
00565 static size_t battfs_write(struct KFile *fd, const void *_buf, size_t size)
00566 {
00567 BattFs *fdb = BATTFS_CAST(fd);
00568 BattFsSuper *disk = fdb->disk;
00569 const uint8_t *buf = (const uint8_t *)_buf;
00570
00571 size_t total_write = 0;
00572 pgoff_t pg_offset;
00573 pgaddr_t addr_offset;
00574 pgaddr_t wr_len;
00575 BattFsPageHeader curr_hdr;
00576 pgcnt_t new_page;
00577
00578 if (fd->seek_pos < 0)
00579 {
00580 fdb->errors |= BATTFS_NEGATIVE_SEEK_ERR;
00581 return total_write;
00582 }
00583
00584 if (fd->seek_pos > fd->size)
00585 {
00586 if (!readHdr(disk, fdb->start[fdb->max_off], &curr_hdr))
00587 {
00588 fdb->errors |= BATTFS_DISK_READ_ERR;
00589 return total_write;
00590 }
00591
00592
00593
00594
00595
00596
00597
00598 if (kblock_buffered(disk->dev)
00599 && ((fdb->start[fdb->max_off] != kblock_cachedBlock(disk->dev)) || !kblock_cacheDirty(disk->dev)))
00600 {
00601 new_page = renewPage(disk, fdb->start[fdb->max_off]);
00602 if (new_page == NO_SPACE)
00603 {
00604 fdb->errors |= BATTFS_DISK_SPACEOVER_ERR;
00605 return total_write;
00606 }
00607
00608 kblock_copy(disk->dev, fdb->start[fdb->max_off], new_page);
00609 fdb->start[fdb->max_off] = new_page;
00610 }
00611 else
00612 new_page = fdb->start[fdb->max_off];
00613
00614
00615 uint8_t dummy = 0;
00616
00617 pgaddr_t zero_bytes = MIN(fd->seek_pos - fd->size, (kfile_off_t)(disk->data_size - curr_hdr.fill));
00618 while (zero_bytes--)
00619 {
00620 if (kblock_write(disk->dev, new_page, &dummy, curr_hdr.fill, 1) != 1)
00621 {
00622 fdb->errors |= BATTFS_DISK_WRITE_ERR;
00623 return total_write;
00624 }
00625 curr_hdr.fill++;
00626 fd->size++;
00627 disk->free_bytes--;
00628 }
00629 curr_hdr.seq++;
00630 if (!writeHdr(disk, new_page, &curr_hdr))
00631 {
00632 fdb->errors |= BATTFS_DISK_WRITE_ERR;
00633 return total_write;
00634 }
00635
00636
00637 pgoff_t missing_pages = fd->seek_pos / disk->data_size - fdb->max_off;
00638
00639 LOG_INFO("missing pages: %d\n", missing_pages);
00640
00641 while (missing_pages--)
00642 {
00643 zero_bytes = MIN((kfile_off_t)disk->data_size, fd->seek_pos - fd->size);
00644
00645 new_page = allocateNewPage(disk, (fdb->start - disk->page_array) + fdb->max_off + 1, fdb->inode);
00646 if (new_page == NO_SPACE)
00647 {
00648 fdb->errors |= BATTFS_DISK_SPACEOVER_ERR;
00649 return total_write;
00650 }
00651
00652
00653
00654
00655 for (pgaddr_t off = 0; off < disk->data_size; off++)
00656 {
00657 if (kblock_write(disk->dev, new_page, &dummy, off, 1) != 1)
00658 {
00659 fdb->errors |= BATTFS_DISK_WRITE_ERR;
00660 return total_write;
00661 }
00662 }
00663 curr_hdr.inode = fdb->inode;
00664 curr_hdr.pgoff = ++fdb->max_off;
00665 curr_hdr.fill = zero_bytes;
00666 curr_hdr.seq = 0;
00667
00668 if (!writeHdr(disk, new_page, &curr_hdr))
00669 {
00670 fdb->errors |= BATTFS_DISK_WRITE_ERR;
00671 return total_write;
00672 }
00673
00674
00675 fd->size += zero_bytes;
00676 disk->free_bytes -= zero_bytes;
00677 }
00678 }
00679
00680 while (size)
00681 {
00682 pg_offset = fd->seek_pos / disk->data_size;
00683 addr_offset = fd->seek_pos % disk->data_size;
00684 wr_len = MIN(size, (size_t)(disk->data_size - addr_offset));
00685
00686
00687 if (pg_offset > fdb->max_off)
00688 {
00689 LOG_INFO("New page needed, pg_offset %d, pos %d\n", pg_offset, (int)((fdb->start - disk->page_array) + pg_offset));
00690
00691 new_page = allocateNewPage(disk, (fdb->start - disk->page_array) + pg_offset, fdb->inode);
00692 if (new_page == NO_SPACE)
00693 {
00694 fdb->errors |= BATTFS_DISK_SPACEOVER_ERR;
00695 return total_write;
00696 }
00697
00698 curr_hdr.inode = fdb->inode;
00699 curr_hdr.pgoff = pg_offset;
00700 curr_hdr.fill = 0;
00701 curr_hdr.seq = 0;
00702 fdb->max_off = pg_offset;
00703 }
00704 else
00705 {
00706 if (!readHdr(disk, fdb->start[pg_offset], &curr_hdr))
00707 {
00708 fdb->errors |= BATTFS_DISK_READ_ERR;
00709 return total_write;
00710 }
00711
00712
00713 if (kblock_buffered(disk->dev)
00714 && ((fdb->start[fdb->max_off] != kblock_cachedBlock(disk->dev)) || !kblock_cacheDirty(disk->dev)))
00715 {
00716 new_page = renewPage(disk, fdb->start[pg_offset]);
00717 if (new_page == NO_SPACE)
00718 {
00719 fdb->errors |= BATTFS_DISK_SPACEOVER_ERR;
00720 return total_write;
00721 }
00722
00723 LOG_INFO("Re-writing page %d to %d\n", fdb->start[pg_offset], new_page);
00724 if (kblock_copy(disk->dev, fdb->start[pg_offset], new_page) != 0)
00725 {
00726 fdb->errors |= BATTFS_DISK_WRITE_ERR;
00727 return total_write;
00728 }
00729 fdb->start[pg_offset] = new_page;
00730 }
00731 else
00732 {
00733 LOG_INFO("Using cached block %d\n", fdb->start[pg_offset]);
00734 new_page = fdb->start[pg_offset];
00735 }
00736
00737 curr_hdr.seq++;
00738 }
00739
00740 if (kblock_write(disk->dev, new_page, buf, addr_offset, wr_len) != wr_len)
00741 {
00742 fdb->errors |= BATTFS_DISK_WRITE_ERR;
00743 return total_write;
00744 }
00745
00746 size -= wr_len;
00747 fd->seek_pos += wr_len;
00748 total_write += wr_len;
00749 buf += wr_len;
00750 fill_t fill_delta = MAX((int32_t)(addr_offset + wr_len) - curr_hdr.fill, (int32_t)0);
00751 disk->free_bytes -= fill_delta;
00752 fd->size += fill_delta;
00753 curr_hdr.fill += fill_delta;
00754
00755 if (!writeHdr(disk, new_page, &curr_hdr))
00756 {
00757 fdb->errors |= BATTFS_DISK_WRITE_ERR;
00758 return total_write;
00759 }
00760
00761
00762 }
00763 return total_write;
00764 }
00765
00766
00771 static size_t battfs_read(struct KFile *fd, void *_buf, size_t size)
00772 {
00773 BattFs *fdb = BATTFS_CAST(fd);
00774 BattFsSuper *disk = fdb->disk;
00775 uint8_t *buf = (uint8_t *)_buf;
00776
00777 size_t total_read = 0;
00778 pgoff_t pg_offset;
00779 pgaddr_t addr_offset;
00780 pgaddr_t read_len;
00781
00782 if (fd->seek_pos < 0)
00783 {
00784 fdb->errors |= BATTFS_NEGATIVE_SEEK_ERR;
00785 return total_read;
00786 }
00787
00788 size = MIN((kfile_off_t)size, MAX(fd->size - fd->seek_pos, (kfile_off_t)0));
00789
00790 while (size)
00791 {
00792 pg_offset = fd->seek_pos / disk->data_size;
00793 addr_offset = fd->seek_pos % disk->data_size;
00794 read_len = MIN(size, (size_t)(disk->data_size - addr_offset));
00795
00796
00797
00798 if (kblock_read(disk->dev, fdb->start[pg_offset], buf, addr_offset, read_len) != read_len)
00799 {
00800 fdb->errors |= BATTFS_DISK_READ_ERR;
00801 return total_read;
00802 }
00803
00804 #ifdef _DEBUG
00805 BattFsPageHeader hdr;
00806 readHdr(disk, fdb->start[pg_offset], &hdr);
00807 ASSERT(hdr.inode == fdb->inode);
00808 #endif
00809
00810 size -= read_len;
00811 fd->seek_pos += read_len;
00812 total_read += read_len;
00813 buf += read_len;
00814 }
00815 return total_read;
00816 }
00817
00818
00827 static bool findFile(BattFsSuper *disk, inode_t inode, pgcnt_t *last)
00828 {
00829 BattFsPageHeader hdr;
00830 pgcnt_t first = 0, page;
00831 *last = disk->free_page_start;
00832 fcs_t fcs;
00833
00834 while (first < *last)
00835 {
00836 page = (first + *last) / 2;
00837 LOG_INFO("first %d, last %d, page %d\n", first, *last, page);
00838 if (!readHdr(disk, disk->page_array[page], &hdr))
00839 return false;
00840 LOG_INFO("inode read: %d\n", hdr.inode);
00841 fcs = computeFcs(&hdr);
00842 if (hdr.fcs == fcs && hdr.inode == inode)
00843 {
00844 *last = page - hdr.pgoff;
00845 LOG_INFO("Found: %d\n", *last);
00846 return true;
00847 }
00848 else if (hdr.fcs == fcs && hdr.inode < inode)
00849 first = page + 1;
00850 else
00851 *last = page;
00852 }
00853 LOG_INFO("Not found: last %d\n", *last);
00854 return false;
00855 }
00856
00860 bool battfs_fileExists(BattFsSuper *disk, inode_t inode)
00861 {
00862 pgcnt_t dummy;
00863 return findFile(disk, inode, &dummy);
00864 }
00865
00871 static file_size_t countFileSize(BattFsSuper *disk, pgcnt_t *start, inode_t inode)
00872 {
00873 file_size_t size = 0;
00874 BattFsPageHeader hdr;
00875
00876 while (start < &disk->page_array[disk->free_page_start])
00877 {
00878 if (!readHdr(disk, *start++, &hdr))
00879 return EOF;
00880 if (hdr.fcs == computeFcs(&hdr) && hdr.inode == inode)
00881 size += hdr.fill;
00882 else
00883 break;
00884 }
00885 return size;
00886 }
00887
00888 static int battfs_error(struct KFile *fd)
00889 {
00890 BattFs *fdb = BATTFS_CAST(fd);
00891 return fdb->errors;
00892 }
00893
00894
00895 static void battfs_clearerr(struct KFile *fd)
00896 {
00897 BattFs *fdb = BATTFS_CAST(fd);
00898 fdb->errors = 0;
00899 }
00900
00906 bool battfs_fileopen(BattFsSuper *disk, BattFs *fd, inode_t inode, filemode_t mode)
00907 {
00908 Node *n;
00909
00910 memset(fd, 0, sizeof(*fd));
00911
00912
00913 pgcnt_t start_pos;
00914 if (!findFile(disk, inode, &start_pos))
00915 {
00916 LOG_INFO("file %d not found\n", inode);
00917 if (!(mode & BATTFS_CREATE))
00918 {
00919 fd->errors |= BATTFS_FILE_NOT_FOUND_ERR;
00920 return false;
00921 }
00922
00923 BattFsPageHeader hdr;
00924
00925 if (allocateNewPage(disk, start_pos, inode) == NO_SPACE)
00926 {
00927 fd->errors |= BATTFS_DISK_SPACEOVER_ERR;
00928 return false;
00929 }
00930
00931 hdr.inode = inode;
00932 hdr.pgoff = 0;
00933 hdr.fill = 0;
00934 hdr.seq = 0;
00935 if (!writeHdr(disk, disk->page_array[start_pos], &hdr))
00936 {
00937 fd->errors |= BATTFS_DISK_WRITE_ERR;
00938 return false;
00939 }
00940 }
00941 fd->start = &disk->page_array[start_pos];
00942 LOG_INFO("Start pos %d\n", start_pos);
00943
00944
00945 if ((fd->fd.size = countFileSize(disk, fd->start, inode)) == EOF)
00946 {
00947 fd->errors |= BATTFS_DISK_READ_ERR;
00948 return false;
00949 }
00950 fd->max_off = fd->fd.size / disk->data_size;
00951
00952
00953 fd->fd.seek_pos = 0;
00954
00955
00956 FOREACH_NODE(n, &disk->file_opened_list)
00957 {
00958 BattFs *file = containerof(n, BattFs, link);
00959 if (file->inode >= inode)
00960 break;
00961 }
00962 INSERT_BEFORE(&fd->link, n);
00963
00964
00965 fd->inode = inode;
00966 fd->mode = mode;
00967 fd->disk = disk;
00968
00969 fd->fd.close = battfs_fileclose;
00970 fd->fd.flush = battfs_flush;
00971 fd->fd.read = battfs_read;
00972 fd->fd.reopen = kfile_genericReopen;
00973 fd->fd.seek = kfile_genericSeek;
00974 fd->fd.write = battfs_write;
00975
00976 fd->fd.error = battfs_error;
00977 fd->fd.clearerr = battfs_clearerr;
00978
00979 DB(fd->fd._type = KFT_BATTFS);
00980
00981 return true;
00982 }
00983
00984
00988 bool battfs_umount(struct BattFsSuper *disk)
00989 {
00990 Node *n;
00991 int res = 0;
00992
00993
00994 FOREACH_NODE(n, &disk->file_opened_list)
00995 {
00996 BattFs *file = containerof(n, BattFs, link);
00997 res += battfs_fileclose(&file->fd);
00998 }
00999
01000
01001 return (kblock_flush(disk->dev) == 0) && (kblock_close(disk->dev) == 0) && (res == 0);
01002 }
01003
01004 #if UNIT_TEST
01005
01006 void battfs_writeTestBlock(KBlock *dev, pgcnt_t page, inode_t inode, seq_t seq, fill_t fill, pgoff_t pgoff)
01007 {
01008 uint8_t buf[BATTFS_HEADER_LEN];
01009 battfs_eraseBlock(dev, page);
01010
01011 BattFsPageHeader hdr;
01012 hdr.inode = inode;
01013 hdr.fill = fill;
01014 hdr.pgoff = pgoff;
01015 hdr.seq = seq;
01016 hdr.fcs = computeFcs(&hdr);
01017
01018 battfs_to_disk(&hdr, buf);
01019
01020 ASSERT(kblock_write(dev, page, buf, dev->blk_size - BATTFS_HEADER_LEN, BATTFS_HEADER_LEN) == BATTFS_HEADER_LEN);
01021 ASSERT(kblock_flush(dev) == 0);
01022 }
01023
01024 void battfs_eraseBlock(KBlock *dev, pgcnt_t page)
01025 {
01026
01027 uint8_t buf[dev->blk_size];
01028 memset(buf, 0xFF, dev->blk_size);
01029 ASSERT(kblock_write(dev, page, buf, 0, dev->blk_size) == dev->blk_size);
01030 ASSERT(kblock_flush(dev) == 0);
01031 }
01032
01033 #endif