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