Nathan Yonkee / Mbed 2 deprecated Nucleo_sinewave_output_copy

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lfs.c Source File

lfs.c

00001 /*
00002  * The little filesystem
00003  *
00004  * Copyright (c) 2017 ARM Limited
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 #include "lfs.h"
00019 #include "lfs_util.h"
00020 
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <assert.h>
00024 
00025 
00026 /// Caching block device operations ///
00027 static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache,
00028         const lfs_cache_t *pcache, lfs_block_t block,
00029         lfs_off_t off, void *buffer, lfs_size_t size) {
00030     uint8_t *data = buffer;
00031     assert(block < lfs->cfg->block_count);
00032 
00033     while (size > 0) {
00034         if (pcache && block == pcache->block && off >= pcache->off &&
00035                 off < pcache->off + lfs->cfg->prog_size) {
00036             // is already in pcache?
00037             lfs_size_t diff = lfs_min(size,
00038                     lfs->cfg->prog_size - (off-pcache->off));
00039             memcpy(data, &pcache->buffer[off-pcache->off], diff);
00040 
00041             data += diff;
00042             off += diff;
00043             size -= diff;
00044             continue;
00045         }
00046 
00047         if (block == rcache->block && off >= rcache->off &&
00048                 off < rcache->off + lfs->cfg->read_size) {
00049             // is already in rcache?
00050             lfs_size_t diff = lfs_min(size,
00051                     lfs->cfg->read_size - (off-rcache->off));
00052             memcpy(data, &rcache->buffer[off-rcache->off], diff);
00053 
00054             data += diff;
00055             off += diff;
00056             size -= diff;
00057             continue;
00058         }
00059 
00060         if (off % lfs->cfg->read_size == 0 && size >= lfs->cfg->read_size) {
00061             // bypass cache?
00062             lfs_size_t diff = size - (size % lfs->cfg->read_size);
00063             int err = lfs->cfg->read(lfs->cfg, block, off, data, diff);
00064             if (err) {
00065                 return err;
00066             }
00067 
00068             data += diff;
00069             off += diff;
00070             size -= diff;
00071             continue;
00072         }
00073 
00074         // load to cache, first condition can no longer fail
00075         rcache->block = block;
00076         rcache->off = off - (off % lfs->cfg->read_size);
00077         int err = lfs->cfg->read(lfs->cfg, rcache->block,
00078                 rcache->off, rcache->buffer, lfs->cfg->read_size);
00079         if (err) {
00080             return err;
00081         }
00082     }
00083 
00084     return 0;
00085 }
00086 
00087 static int lfs_cache_cmp(lfs_t *lfs, lfs_cache_t *rcache,
00088         const lfs_cache_t *pcache, lfs_block_t block,
00089         lfs_off_t off, const void *buffer, lfs_size_t size) {
00090     const uint8_t *data = buffer;
00091 
00092     for (lfs_off_t i = 0; i < size; i++) {
00093         uint8_t c;
00094         int err = lfs_cache_read(lfs, rcache, pcache,
00095                 block, off+i, &c, 1);
00096         if (err) {
00097             return err;
00098         }
00099 
00100         if (c != data[i]) {
00101             return false;
00102         }
00103     }
00104 
00105     return true;
00106 }
00107 
00108 static int lfs_cache_crc(lfs_t *lfs, lfs_cache_t *rcache,
00109         const lfs_cache_t *pcache, lfs_block_t block,
00110         lfs_off_t off, lfs_size_t size, uint32_t *crc) {
00111     for (lfs_off_t i = 0; i < size; i++) {
00112         uint8_t c;
00113         int err = lfs_cache_read(lfs, rcache, pcache,
00114                 block, off+i, &c, 1);
00115         if (err) {
00116             return err;
00117         }
00118 
00119         lfs_crc(crc, &c, 1);
00120     }
00121 
00122     return 0;
00123 }
00124 
00125 static int lfs_cache_flush(lfs_t *lfs,
00126         lfs_cache_t *pcache, lfs_cache_t *rcache) {
00127     if (pcache->block != 0xffffffff) {
00128         int err = lfs->cfg->prog(lfs->cfg, pcache->block,
00129                 pcache->off, pcache->buffer, lfs->cfg->prog_size);
00130         if (err) {
00131             return err;
00132         }
00133 
00134         if (rcache) {
00135             int res = lfs_cache_cmp(lfs, rcache, NULL, pcache->block,
00136                     pcache->off, pcache->buffer, lfs->cfg->prog_size);
00137             if (res < 0) {
00138                 return res;
00139             }
00140 
00141             if (!res) {
00142                 return LFS_ERR_CORRUPT;
00143             }
00144         }
00145 
00146         pcache->block = 0xffffffff;
00147     }
00148 
00149     return 0;
00150 }
00151 
00152 static int lfs_cache_prog(lfs_t *lfs, lfs_cache_t *pcache,
00153         lfs_cache_t *rcache, lfs_block_t block,
00154         lfs_off_t off, const void *buffer, lfs_size_t size) {
00155     const uint8_t *data = buffer;
00156     assert(block < lfs->cfg->block_count);
00157 
00158     while (size > 0) {
00159         if (block == pcache->block && off >= pcache->off &&
00160                 off < pcache->off + lfs->cfg->prog_size) {
00161             // is already in pcache?
00162             lfs_size_t diff = lfs_min(size,
00163                     lfs->cfg->prog_size - (off-pcache->off));
00164             memcpy(&pcache->buffer[off-pcache->off], data, diff);
00165 
00166             data += diff;
00167             off += diff;
00168             size -= diff;
00169 
00170             if (off % lfs->cfg->prog_size == 0) {
00171                 // eagerly flush out pcache if we fill up
00172                 int err = lfs_cache_flush(lfs, pcache, rcache);
00173                 if (err) {
00174                     return err;
00175                 }
00176             }
00177 
00178             continue;
00179         }
00180 
00181         // pcache must have been flushed, either by programming and
00182         // entire block or manually flushing the pcache
00183         assert(pcache->block == 0xffffffff);
00184 
00185         if (off % lfs->cfg->prog_size == 0 &&
00186                 size >= lfs->cfg->prog_size) {
00187             // bypass pcache?
00188             lfs_size_t diff = size - (size % lfs->cfg->prog_size);
00189             int err = lfs->cfg->prog(lfs->cfg, block, off, data, diff);
00190             if (err) {
00191                 return err;
00192             }
00193 
00194             if (rcache) {
00195                 int res = lfs_cache_cmp(lfs, rcache, NULL,
00196                         block, off, data, diff);
00197                 if (res < 0) {
00198                     return res;
00199                 }
00200 
00201                 if (!res) {
00202                     return LFS_ERR_CORRUPT;
00203                 }
00204             }
00205 
00206             data += diff;
00207             off += diff;
00208             size -= diff;
00209             continue;
00210         }
00211 
00212         // prepare pcache, first condition can no longer fail
00213         pcache->block = block;
00214         pcache->off = off - (off % lfs->cfg->prog_size);
00215     }
00216 
00217     return 0;
00218 }
00219 
00220 
00221 /// General lfs block device operations ///
00222 static int lfs_bd_read(lfs_t *lfs, lfs_block_t block,
00223         lfs_off_t off, void *buffer, lfs_size_t size) {
00224     // if we ever do more than writes to alternating pairs,
00225     // this may need to consider pcache
00226     return lfs_cache_read(lfs, &lfs->rcache, NULL,
00227             block, off, buffer, size);
00228 }
00229 
00230 static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block,
00231         lfs_off_t off, const void *buffer, lfs_size_t size) {
00232     return lfs_cache_prog(lfs, &lfs->pcache, NULL,
00233             block, off, buffer, size);
00234 }
00235 
00236 static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
00237         lfs_off_t off, const void *buffer, lfs_size_t size) {
00238     return lfs_cache_cmp(lfs, &lfs->rcache, NULL, block, off, buffer, size);
00239 }
00240 
00241 static int lfs_bd_crc(lfs_t *lfs, lfs_block_t block,
00242         lfs_off_t off, lfs_size_t size, uint32_t *crc) {
00243     return lfs_cache_crc(lfs, &lfs->rcache, NULL, block, off, size, crc);
00244 }
00245 
00246 static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
00247     return lfs->cfg->erase(lfs->cfg, block);
00248 }
00249 
00250 static int lfs_bd_sync(lfs_t *lfs) {
00251     lfs->rcache.block = 0xffffffff;
00252 
00253     int err = lfs_cache_flush(lfs, &lfs->pcache, NULL);
00254     if (err) {
00255         return err;
00256     }
00257 
00258     return lfs->cfg->sync(lfs->cfg);
00259 }
00260 
00261 
00262 /// Internal operations predeclared here ///
00263 int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
00264 static int lfs_pred(lfs_t *lfs, const lfs_block_t dir[2], lfs_dir_t *pdir);
00265 static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2],
00266         lfs_dir_t *parent, lfs_entry_t *entry);
00267 static int lfs_moved(lfs_t *lfs, const void *e);
00268 static int lfs_relocate(lfs_t *lfs,
00269         const lfs_block_t oldpair[2], const lfs_block_t newpair[2]);
00270 int lfs_deorphan(lfs_t *lfs);
00271 
00272 
00273 /// Block allocator ///
00274 static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
00275     lfs_t *lfs = p;
00276 
00277     lfs_block_t off = (((lfs_soff_t)(block - lfs->free.begin)
00278                 % (lfs_soff_t)(lfs->cfg->block_count))
00279             + lfs->cfg->block_count) % lfs->cfg->block_count;
00280 
00281     if (off < lfs->cfg->lookahead) {
00282         lfs->free.buffer[off / 32] |= 1U << (off % 32);
00283     }
00284 
00285     return 0;
00286 }
00287 
00288 static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
00289     while (true) {
00290         while (true) {
00291             // check if we have looked at all blocks since last ack
00292             if (lfs->free.begin + lfs->free.off == lfs->free.end) {
00293                 LFS_WARN("No more free space %ld", lfs->free.end);
00294                 return LFS_ERR_NOSPC;
00295             }
00296 
00297             if (lfs->free.off >= lfs_min(
00298                     lfs->cfg->lookahead, lfs->cfg->block_count)) {
00299                 break;
00300             }
00301 
00302             lfs_block_t off = lfs->free.off;
00303             lfs->free.off += 1;
00304 
00305             if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) {
00306                 // found a free block
00307                 *block = (lfs->free.begin + off) % lfs->cfg->block_count;
00308                 return 0;
00309             }
00310         }
00311 
00312         lfs->free.begin += lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
00313         lfs->free.off = 0;
00314 
00315         // find mask of free blocks from tree
00316         memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8);
00317         int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs);
00318         if (err) {
00319             return err;
00320         }
00321     }
00322 }
00323 
00324 static void lfs_alloc_ack(lfs_t *lfs) {
00325     lfs->free.end = lfs->free.begin + lfs->free.off + lfs->cfg->block_count;
00326 }
00327 
00328 
00329 /// Metadata pair and directory operations ///
00330 static inline void lfs_pairswap(lfs_block_t pair[2]) {
00331     lfs_block_t t = pair[0];
00332     pair[0] = pair[1];
00333     pair[1] = t;
00334 }
00335 
00336 static inline bool lfs_pairisnull(const lfs_block_t pair[2]) {
00337     return pair[0] == 0xffffffff || pair[1] == 0xffffffff;
00338 }
00339 
00340 static inline int lfs_paircmp(
00341         const lfs_block_t paira[2],
00342         const lfs_block_t pairb[2]) {
00343     return !(paira[0] == pairb[0] || paira[1] == pairb[1] ||
00344              paira[0] == pairb[1] || paira[1] == pairb[0]);
00345 }
00346 
00347 static inline bool lfs_pairsync(
00348         const lfs_block_t paira[2],
00349         const lfs_block_t pairb[2]) {
00350     return (paira[0] == pairb[0] && paira[1] == pairb[1]) ||
00351            (paira[0] == pairb[1] && paira[1] == pairb[0]);
00352 }
00353 
00354 static inline lfs_size_t lfs_entry_size(const lfs_entry_t *entry) {
00355     return 4 + entry->d.elen + entry->d.alen + entry->d.nlen;
00356 }
00357 
00358 static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) {
00359     // allocate pair of dir blocks
00360     for (int i = 0; i < 2; i++) {
00361         int err = lfs_alloc(lfs, &dir->pair[i]);
00362         if (err) {
00363             return err;
00364         }
00365     }
00366 
00367     // rather than clobbering one of the blocks we just pretend
00368     // the revision may be valid
00369     int err = lfs_bd_read(lfs, dir->pair[0], 0, &dir->d.rev, 4);
00370     if (err) {
00371         return err;
00372     }
00373 
00374     // set defaults
00375     dir->d.rev += 1;
00376     dir->d.size = sizeof(dir->d)+4;
00377     dir->d.tail[0] = 0xffffffff;
00378     dir->d.tail[1] = 0xffffffff;
00379     dir->off = sizeof(dir->d);
00380 
00381     // don't write out yet, let caller take care of that
00382     return 0;
00383 }
00384 
00385 static int lfs_dir_fetch(lfs_t *lfs,
00386         lfs_dir_t *dir, const lfs_block_t pair[2]) {
00387     // copy out pair, otherwise may be aliasing dir
00388     const lfs_block_t tpair[2] = {pair[0], pair[1]};
00389     bool valid = false;
00390 
00391     // check both blocks for the most recent revision
00392     for (int i = 0; i < 2; i++) {
00393         struct lfs_disk_dir test;
00394         int err = lfs_bd_read(lfs, tpair[i], 0, &test, sizeof(test));
00395         if (err) {
00396             return err;
00397         }
00398 
00399         if (valid && lfs_scmp(test.rev, dir->d.rev) < 0) {
00400             continue;
00401         }
00402 
00403         if ((0x7fffffff & test.size) < sizeof(test)+4 ||
00404             (0x7fffffff & test.size) > lfs->cfg->block_size) {
00405             continue;
00406         }
00407 
00408         uint32_t crc = 0xffffffff;
00409         lfs_crc(&crc, &test, sizeof(test));
00410         err = lfs_bd_crc(lfs, tpair[i], sizeof(test),
00411                 (0x7fffffff & test.size) - sizeof(test), &crc);
00412         if (err) {
00413             return err;
00414         }
00415 
00416         if (crc != 0) {
00417             continue;
00418         }
00419 
00420         valid = true;
00421 
00422         // setup dir in case it's valid
00423         dir->pair[0] = tpair[(i+0) % 2];
00424         dir->pair[1] = tpair[(i+1) % 2];
00425         dir->off = sizeof(dir->d);
00426         dir->d = test;
00427     }
00428 
00429     if (!valid) {
00430         LFS_ERROR("Corrupted dir pair at %ld %ld", tpair[0], tpair[1]);
00431         return LFS_ERR_CORRUPT;
00432     }
00433 
00434     return 0;
00435 }
00436 
00437 struct lfs_region {
00438     lfs_off_t oldoff;
00439     lfs_size_t oldlen;
00440     const void *newdata;
00441     lfs_size_t newlen;
00442 };
00443 
00444 static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
00445         const struct lfs_region *regions, int count) {
00446     // increment revision count
00447     dir->d.rev += 1;
00448 
00449     // keep pairs in order such that pair[0] is most recent
00450     lfs_pairswap(dir->pair);
00451     for (int i = 0; i < count; i++) {
00452         dir->d.size += regions[i].newlen - regions[i].oldlen;
00453     }
00454 
00455     const lfs_block_t oldpair[2] = {dir->pair[0], dir->pair[1]};
00456     bool relocated = false;
00457 
00458     while (true) {
00459         if (true) {
00460             int err = lfs_bd_erase(lfs, dir->pair[0]);
00461             if (err) {
00462                 if (err == LFS_ERR_CORRUPT) {
00463                     goto relocate;
00464                 }
00465                 return err;
00466             }
00467 
00468             uint32_t crc = 0xffffffff;
00469             lfs_crc(&crc, &dir->d, sizeof(dir->d));
00470             err = lfs_bd_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d));
00471             if (err) {
00472                 if (err == LFS_ERR_CORRUPT) {
00473                     goto relocate;
00474                 }
00475                 return err;
00476             }
00477 
00478             int i = 0;
00479             lfs_off_t oldoff = sizeof(dir->d);
00480             lfs_off_t newoff = sizeof(dir->d);
00481             while (newoff < (0x7fffffff & dir->d.size)-4) {
00482                 if (i < count && regions[i].oldoff == oldoff) {
00483                     lfs_crc(&crc, regions[i].newdata, regions[i].newlen);
00484                     int err = lfs_bd_prog(lfs, dir->pair[0],
00485                             newoff, regions[i].newdata, regions[i].newlen);
00486                     if (err) {
00487                         if (err == LFS_ERR_CORRUPT) {
00488                             goto relocate;
00489                         }
00490                         return err;
00491                     }
00492 
00493                     oldoff += regions[i].oldlen;
00494                     newoff += regions[i].newlen;
00495                     i += 1;
00496                 } else {
00497                     uint8_t data;
00498                     int err = lfs_bd_read(lfs, oldpair[1], oldoff, &data, 1);
00499                     if (err) {
00500                         return err;
00501                     }
00502 
00503                     lfs_crc(&crc, &data, 1);
00504                     err = lfs_bd_prog(lfs, dir->pair[0], newoff, &data, 1);
00505                     if (err) {
00506                         if (err == LFS_ERR_CORRUPT) {
00507                             goto relocate;
00508                         }
00509                         return err;
00510                     }
00511 
00512                     oldoff += 1;
00513                     newoff += 1;
00514                 }
00515             }
00516 
00517             err = lfs_bd_prog(lfs, dir->pair[0], newoff, &crc, 4);
00518             if (err) {
00519                 if (err == LFS_ERR_CORRUPT) {
00520                     goto relocate;
00521                 }
00522                 return err;
00523             }
00524 
00525             err = lfs_bd_sync(lfs);
00526             if (err) {
00527                 if (err == LFS_ERR_CORRUPT) {
00528                     goto relocate;
00529                 }
00530                 return err;
00531             }
00532 
00533             // successful commit, check checksum to make sure
00534             uint32_t ncrc = 0xffffffff;
00535             err = lfs_bd_crc(lfs, dir->pair[0], 0,
00536                     (0x7fffffff & dir->d.size)-4, &ncrc);
00537             if (err) {
00538                 return err;
00539             }
00540 
00541             if (ncrc != crc) {
00542                 goto relocate;
00543             }
00544         }
00545 
00546         break;
00547 relocate:
00548         //commit was corrupted
00549         LFS_DEBUG("Bad block at %ld", dir->pair[0]);
00550 
00551         // drop caches and prepare to relocate block
00552         relocated = true;
00553         lfs->pcache.block = 0xffffffff;
00554 
00555         // can't relocate superblock, filesystem is now frozen
00556         if (lfs_paircmp(oldpair, (const lfs_block_t[2]){0, 1}) == 0) {
00557             LFS_WARN("Superblock %ld has become unwritable", oldpair[0]);
00558             return LFS_ERR_CORRUPT;
00559         }
00560 
00561         // relocate half of pair
00562         int err = lfs_alloc(lfs, &dir->pair[0]);
00563         if (err) {
00564             return err;
00565         }
00566     }
00567 
00568     if (relocated) {
00569         // update references if we relocated
00570         LFS_DEBUG("Relocating %ld %ld to %ld %ld",
00571                 oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]);
00572         int err = lfs_relocate(lfs, oldpair, dir->pair);
00573         if (err) {
00574             return err;
00575         }
00576     }
00577 
00578     // shift over any directories that are affected
00579     for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
00580         if (lfs_paircmp(d->pair, dir->pair) == 0) {
00581             d->pair[0] = dir->pair[0];
00582             d->pair[1] = dir->pair[1];
00583         }
00584     }
00585 
00586     return 0;
00587 }
00588 
00589 static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir,
00590         const lfs_entry_t *entry, const void *data) {
00591     return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
00592             {entry->off, sizeof(entry->d), &entry->d, sizeof(entry->d)},
00593             {entry->off+sizeof(entry->d), entry->d.nlen, data, entry->d.nlen}
00594         }, data ? 2 : 1);
00595 }
00596 
00597 static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
00598         lfs_entry_t *entry, const void *data) {
00599     // check if we fit, if top bit is set we do not and move on
00600     while (true) {
00601         if (dir->d.size + lfs_entry_size(entry) <= lfs->cfg->block_size) {
00602             entry->off = dir->d.size - 4;
00603             return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
00604                     {entry->off, 0, &entry->d, sizeof(entry->d)},
00605                     {entry->off, 0, data, entry->d.nlen}
00606                 }, 2);
00607         }
00608 
00609         // we need to allocate a new dir block
00610         if (!(0x80000000 & dir->d.size)) {
00611             lfs_dir_t newdir;
00612             int err = lfs_dir_alloc(lfs, &newdir);
00613             if (err) {
00614                 return err;
00615             }
00616 
00617             newdir.d.tail[0] = dir->d.tail[0];
00618             newdir.d.tail[1] = dir->d.tail[1];
00619             entry->off = newdir.d.size - 4;
00620             err = lfs_dir_commit(lfs, &newdir, (struct lfs_region[]){
00621                     {entry->off, 0, &entry->d, sizeof(entry->d)},
00622                     {entry->off, 0, data, entry->d.nlen}
00623                 }, 2);
00624             if (err) {
00625                 return err;
00626             }
00627 
00628             dir->d.size |= 0x80000000;
00629             dir->d.tail[0] = newdir.pair[0];
00630             dir->d.tail[1] = newdir.pair[1];
00631             return lfs_dir_commit(lfs, dir, NULL, 0);
00632         }
00633 
00634         int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
00635         if (err) {
00636             return err;
00637         }
00638     }
00639 }
00640 
00641 static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
00642     // check if we should just drop the directory block
00643     if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4
00644             + lfs_entry_size(entry)) {
00645         lfs_dir_t pdir;
00646         int res = lfs_pred(lfs, dir->pair, &pdir);
00647         if (res < 0) {
00648             return res;
00649         }
00650 
00651         if (pdir.d.size & 0x80000000) {
00652             pdir.d.size &= dir->d.size | 0x7fffffff;
00653             pdir.d.tail[0] = dir->d.tail[0];
00654             pdir.d.tail[1] = dir->d.tail[1];
00655             return lfs_dir_commit(lfs, &pdir, NULL, 0);
00656         }
00657     }
00658 
00659     // shift out the entry
00660     int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){
00661             {entry->off, lfs_entry_size(entry), NULL, 0},
00662         }, 1);
00663     if (err) {
00664         return err;
00665     }
00666 
00667     // shift over any files/directories that are affected
00668     for (lfs_file_t *f = lfs->files; f; f = f->next) {
00669         if (lfs_paircmp(f->pair, dir->pair) == 0) {
00670             if (f->poff == entry->off) {
00671                 f->pair[0] = 0xffffffff;
00672                 f->pair[1] = 0xffffffff;
00673             } else if (f->poff > entry->off) {
00674                 f->poff -= lfs_entry_size(entry);
00675             }
00676         }
00677     }
00678 
00679     for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
00680         if (lfs_paircmp(d->pair, dir->pair) == 0) {
00681             if (d->off > entry->off) {
00682                 d->off -= lfs_entry_size(entry);
00683                 d->pos -= lfs_entry_size(entry);
00684             }
00685         }
00686     }
00687 
00688     return 0;
00689 }
00690 
00691 static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
00692     while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) {
00693         if (!(0x80000000 & dir->d.size)) {
00694             entry->off = dir->off;
00695             return LFS_ERR_NOENT;
00696         }
00697 
00698         int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
00699         if (err) {
00700             return err;
00701         }
00702 
00703         dir->off = sizeof(dir->d);
00704         dir->pos += sizeof(dir->d) + 4;
00705     }
00706 
00707     int err = lfs_bd_read(lfs, dir->pair[0], dir->off,
00708             &entry->d, sizeof(entry->d));
00709     if (err) {
00710         return err;
00711     }
00712 
00713     entry->off = dir->off;
00714     dir->off += lfs_entry_size(entry);
00715     dir->pos += lfs_entry_size(entry);
00716     return 0;
00717 }
00718 
00719 static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
00720         lfs_entry_t *entry, const char **path) {
00721     const char *pathname = *path;
00722     size_t pathlen;
00723 
00724     while (true) {
00725     nextname:
00726         // skip slashes
00727         pathname += strspn(pathname, "/");
00728         pathlen = strcspn(pathname, "/");
00729 
00730         // skip '.' and root '..'
00731         if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) ||
00732             (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) {
00733             pathname += pathlen;
00734             goto nextname;
00735         }
00736 
00737         // skip if matched by '..' in name
00738         const char *suffix = pathname + pathlen;
00739         size_t sufflen;
00740         int depth = 1;
00741         while (true) {
00742             suffix += strspn(suffix, "/");
00743             sufflen = strcspn(suffix, "/");
00744             if (sufflen == 0) {
00745                 break;
00746             }
00747 
00748             if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
00749                 depth -= 1;
00750                 if (depth == 0) {
00751                     pathname = suffix + sufflen;
00752                     goto nextname;
00753                 }
00754             } else {
00755                 depth += 1;
00756             }
00757 
00758             suffix += sufflen;
00759         }
00760 
00761         // update what we've found
00762         *path = pathname;
00763 
00764         // find path
00765         while (true) {
00766             int err = lfs_dir_next(lfs, dir, entry);
00767             if (err) {
00768                 return err;
00769             }
00770 
00771             if (((0x7f & entry->d.type) != LFS_TYPE_REG &&
00772                  (0x7f & entry->d.type) != LFS_TYPE_DIR) ||
00773                 entry->d.nlen != pathlen) {
00774                 continue;
00775             }
00776 
00777             int res = lfs_bd_cmp(lfs, dir->pair[0],
00778                     entry->off + 4+entry->d.elen+entry->d.alen,
00779                     pathname, pathlen);
00780             if (res < 0) {
00781                 return res;
00782             }
00783 
00784             // found match
00785             if (res) {
00786                 break;
00787             }
00788         }
00789 
00790         // check that entry has not been moved
00791         if (entry->d.type & 0x80) {
00792             int moved = lfs_moved(lfs, &entry->d.u);
00793             if (moved < 0 || moved) {
00794                 return (moved < 0) ? moved : LFS_ERR_NOENT;
00795             }
00796 
00797             entry->d.type &= ~0x80;
00798         }
00799 
00800         pathname += pathlen;
00801         pathname += strspn(pathname, "/");
00802         if (pathname[0] == '\0') {
00803             return 0;
00804         }
00805 
00806         // continue on if we hit a directory
00807         if (entry->d.type != LFS_TYPE_DIR) {
00808             return LFS_ERR_NOTDIR;
00809         }
00810 
00811         int err = lfs_dir_fetch(lfs, dir, entry->d.u.dir);
00812         if (err) {
00813             return err;
00814         }
00815     }
00816 }
00817 
00818 
00819 /// Top level directory operations ///
00820 int lfs_mkdir(lfs_t *lfs, const char *path) {
00821     // deorphan if we haven't yet, needed at most once after poweron
00822     if (!lfs->deorphaned) {
00823         int err = lfs_deorphan(lfs);
00824         if (err) {
00825             return err;
00826         }
00827     }
00828 
00829     // fetch parent directory
00830     lfs_dir_t cwd;
00831     int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
00832     if (err) {
00833         return err;
00834     }
00835 
00836     lfs_entry_t entry;
00837     err = lfs_dir_find(lfs, &cwd, &entry, &path);
00838     if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) {
00839         return err ? err : LFS_ERR_EXIST;
00840     }
00841 
00842     // build up new directory
00843     lfs_alloc_ack(lfs);
00844 
00845     lfs_dir_t dir;
00846     err = lfs_dir_alloc(lfs, &dir);
00847     if (err) {
00848         return err;
00849     }
00850     dir.d.tail[0] = cwd.d.tail[0];
00851     dir.d.tail[1] = cwd.d.tail[1];
00852 
00853     err = lfs_dir_commit(lfs, &dir, NULL, 0);
00854     if (err) {
00855         return err;
00856     }
00857 
00858     entry.d.type = LFS_TYPE_DIR;
00859     entry.d.elen = sizeof(entry.d) - 4;
00860     entry.d.alen = 0;
00861     entry.d.nlen = strlen(path);
00862     entry.d.u.dir[0] = dir.pair[0];
00863     entry.d.u.dir[1] = dir.pair[1];
00864 
00865     cwd.d.tail[0] = dir.pair[0];
00866     cwd.d.tail[1] = dir.pair[1];
00867 
00868     err = lfs_dir_append(lfs, &cwd, &entry, path);
00869     if (err) {
00870         return err;
00871     }
00872 
00873     lfs_alloc_ack(lfs);
00874     return 0;
00875 }
00876 
00877 int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
00878     dir->pair[0] = lfs->root[0];
00879     dir->pair[1] = lfs->root[1];
00880 
00881     int err = lfs_dir_fetch(lfs, dir, dir->pair);
00882     if (err) {
00883         return err;
00884     }
00885 
00886     // check for root, can only be something like '/././../.'
00887     if (strspn(path, "/.") == strlen(path)) {
00888         dir->head[0] = dir->pair[0];
00889         dir->head[1] = dir->pair[1];
00890         dir->pos = sizeof(dir->d) - 2;
00891         dir->off = sizeof(dir->d);
00892         return 0;
00893     }
00894 
00895     lfs_entry_t entry;
00896     err = lfs_dir_find(lfs, dir, &entry, &path);
00897     if (err) {
00898         return err;
00899     } else if (entry.d.type != LFS_TYPE_DIR) {
00900         return LFS_ERR_NOTDIR;
00901     }
00902 
00903     err = lfs_dir_fetch(lfs, dir, entry.d.u.dir);
00904     if (err) {
00905         return err;
00906     }
00907 
00908     // setup head dir
00909     // special offset for '.' and '..'
00910     dir->head[0] = dir->pair[0];
00911     dir->head[1] = dir->pair[1];
00912     dir->pos = sizeof(dir->d) - 2;
00913     dir->off = sizeof(dir->d);
00914 
00915     // add to list of directories
00916     dir->next = lfs->dirs;
00917     lfs->dirs = dir;
00918 
00919     return 0;
00920 }
00921 
00922 int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
00923     // remove from list of directories
00924     for (lfs_dir_t **p = &lfs->dirs; *p; p = &(*p)->next) {
00925         if (*p == dir) {
00926             *p = dir->next;
00927             break;
00928         }
00929     }
00930 
00931     return 0;
00932 }
00933 
00934 int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
00935     memset(info, 0, sizeof(*info));
00936 
00937     // special offset for '.' and '..'
00938     if (dir->pos == sizeof(dir->d) - 2) {
00939         info->type = LFS_TYPE_DIR;
00940         strcpy(info->name, ".");
00941         dir->pos += 1;
00942         return 1;
00943     } else if (dir->pos == sizeof(dir->d) - 1) {
00944         info->type = LFS_TYPE_DIR;
00945         strcpy(info->name, "..");
00946         dir->pos += 1;
00947         return 1;
00948     }
00949 
00950     lfs_entry_t entry;
00951     while (true) {
00952         int err = lfs_dir_next(lfs, dir, &entry);
00953         if (err) {
00954             return (err == LFS_ERR_NOENT) ? 0 : err;
00955         }
00956 
00957         if ((0x7f & entry.d.type) != LFS_TYPE_REG &&
00958             (0x7f & entry.d.type) != LFS_TYPE_DIR) {
00959             continue;
00960         }
00961 
00962         // check that entry has not been moved
00963         if (entry.d.type & 0x80) {
00964             int moved = lfs_moved(lfs, &entry.d.u);
00965             if (moved < 0) {
00966                 return moved;
00967             }
00968 
00969             if (moved) {
00970                 continue;
00971             }
00972 
00973             entry.d.type &= ~0x80;
00974         }
00975 
00976         break;
00977     }
00978 
00979     info->type = entry.d.type;
00980     if (info->type == LFS_TYPE_REG) {
00981         info->size = entry.d.u.file.size;
00982     }
00983 
00984     int err = lfs_bd_read(lfs, dir->pair[0],
00985             entry.off + 4+entry.d.elen+entry.d.alen,
00986             info->name, entry.d.nlen);
00987     if (err) {
00988         return err;
00989     }
00990 
00991     return 1;
00992 }
00993 
00994 int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
00995     // simply walk from head dir
00996     int err = lfs_dir_rewind(lfs, dir);
00997     if (err) {
00998         return err;
00999     }
01000     dir->pos = off;
01001 
01002     while (off > (0x7fffffff & dir->d.size)) {
01003         off -= 0x7fffffff & dir->d.size;
01004         if (!(0x80000000 & dir->d.size)) {
01005             return LFS_ERR_INVAL;
01006         }
01007 
01008         int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
01009         if (err) {
01010             return err;
01011         }
01012     }
01013 
01014     dir->off = off;
01015     return 0;
01016 }
01017 
01018 lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) {
01019     return dir->pos;
01020 }
01021 
01022 int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) {
01023     // reload the head dir
01024     int err = lfs_dir_fetch(lfs, dir, dir->head);
01025     if (err) {
01026         return err;
01027     }
01028 
01029     dir->pair[0] = dir->head[0];
01030     dir->pair[1] = dir->head[1];
01031     dir->pos = sizeof(dir->d) - 2;
01032     dir->off = sizeof(dir->d);
01033     return 0;
01034 }
01035 
01036 
01037 /// File index list operations ///
01038 static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) {
01039     lfs_off_t size = *off;
01040     lfs_off_t b = lfs->cfg->block_size - 2*4;
01041     lfs_off_t i = size / b;
01042     if (i == 0) {
01043         return 0;
01044     }
01045 
01046     i = (size - 4*(lfs_popc(i-1)+2)) / b;
01047     *off = size - b*i - 4*lfs_popc(i);
01048     return i;
01049 }
01050 
01051 static int lfs_ctz_find(lfs_t *lfs,
01052         lfs_cache_t *rcache, const lfs_cache_t *pcache,
01053         lfs_block_t head, lfs_size_t size,
01054         lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) {
01055     if (size == 0) {
01056         *block = 0xffffffff;
01057         *off = 0;
01058         return 0;
01059     }
01060 
01061     lfs_off_t current = lfs_ctz_index(lfs, &(lfs_off_t){size-1});
01062     lfs_off_t target = lfs_ctz_index(lfs, &pos);
01063 
01064     while (current > target) {
01065         lfs_size_t skip = lfs_min(
01066                 lfs_npw2(current-target+1) - 1,
01067                 lfs_ctz(current));
01068 
01069         int err = lfs_cache_read(lfs, rcache, pcache, head, 4*skip, &head, 4);
01070         if (err) {
01071             return err;
01072         }
01073 
01074         assert(head >= 2 && head <= lfs->cfg->block_count);
01075         current -= 1 << skip;
01076     }
01077 
01078     *block = head;
01079     *off = pos;
01080     return 0;
01081 }
01082 
01083 static int lfs_ctz_extend(lfs_t *lfs,
01084         lfs_cache_t *rcache, lfs_cache_t *pcache,
01085         lfs_block_t head, lfs_size_t size,
01086         lfs_block_t *block, lfs_off_t *off) {
01087     while (true) {
01088         // go ahead and grab a block
01089         lfs_block_t nblock;
01090         int err = lfs_alloc(lfs, &nblock);
01091         if (err) {
01092             return err;
01093         }
01094         assert(nblock >= 2 && nblock <= lfs->cfg->block_count);
01095 
01096         if (true) {
01097             err = lfs_bd_erase(lfs, nblock);
01098             if (err) {
01099                 if (err == LFS_ERR_CORRUPT) {
01100                     goto relocate;
01101                 }
01102                 return err;
01103             }
01104 
01105             if (size == 0) {
01106                 *block = nblock;
01107                 *off = 0;
01108                 return 0;
01109             }
01110 
01111             size -= 1;
01112             lfs_off_t index = lfs_ctz_index(lfs, &size);
01113             size += 1;
01114 
01115             // just copy out the last block if it is incomplete
01116             if (size != lfs->cfg->block_size) {
01117                 for (lfs_off_t i = 0; i < size; i++) {
01118                     uint8_t data;
01119                     int err = lfs_cache_read(lfs, rcache, NULL,
01120                             head, i, &data, 1);
01121                     if (err) {
01122                         return err;
01123                     }
01124 
01125                     err = lfs_cache_prog(lfs, pcache, rcache,
01126                             nblock, i, &data, 1);
01127                     if (err) {
01128                         if (err == LFS_ERR_CORRUPT) {
01129                             goto relocate;
01130                         }
01131                         return err;
01132                     }
01133                 }
01134 
01135                 *block = nblock;
01136                 *off = size;
01137                 return 0;
01138             }
01139 
01140             // append block
01141             index += 1;
01142             lfs_size_t skips = lfs_ctz(index) + 1;
01143 
01144             for (lfs_off_t i = 0; i < skips; i++) {
01145                 int err = lfs_cache_prog(lfs, pcache, rcache,
01146                         nblock, 4*i, &head, 4);
01147                 if (err) {
01148                     if (err == LFS_ERR_CORRUPT) {
01149                         goto relocate;
01150                     }
01151                     return err;
01152                 }
01153 
01154                 if (i != skips-1) {
01155                     err = lfs_cache_read(lfs, rcache, NULL,
01156                             head, 4*i, &head, 4);
01157                     if (err) {
01158                         return err;
01159                     }
01160                 }
01161 
01162                 assert(head >= 2 && head <= lfs->cfg->block_count);
01163             }
01164 
01165             *block = nblock;
01166             *off = 4*skips;
01167             return 0;
01168         }
01169 
01170 relocate:
01171         LFS_DEBUG("Bad block at %ld", nblock);
01172 
01173         // just clear cache and try a new block
01174         pcache->block = 0xffffffff;
01175     }
01176 }
01177 
01178 static int lfs_ctz_traverse(lfs_t *lfs,
01179         lfs_cache_t *rcache, const lfs_cache_t *pcache,
01180         lfs_block_t head, lfs_size_t size,
01181         int (*cb)(void*, lfs_block_t), void *data) {
01182     if (size == 0) {
01183         return 0;
01184     }
01185 
01186     lfs_off_t index = lfs_ctz_index(lfs, &(lfs_off_t){size-1});
01187 
01188     while (true) {
01189         int err = cb(data, head);
01190         if (err) {
01191             return err;
01192         }
01193 
01194         if (index == 0) {
01195             return 0;
01196         }
01197 
01198         err = lfs_cache_read(lfs, rcache, pcache, head, 0, &head, 4);
01199         if (err) {
01200             return err;
01201         }
01202 
01203         index -= 1;
01204     }
01205 }
01206 
01207 
01208 /// Top level file operations ///
01209 int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
01210         const char *path, int flags) {
01211     // deorphan if we haven't yet, needed at most once after poweron
01212     if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) {
01213         int err = lfs_deorphan(lfs);
01214         if (err) {
01215             return err;
01216         }
01217     }
01218 
01219     // allocate entry for file if it doesn't exist
01220     lfs_dir_t cwd;
01221     int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
01222     if (err) {
01223         return err;
01224     }
01225 
01226     lfs_entry_t entry;
01227     err = lfs_dir_find(lfs, &cwd, &entry, &path);
01228     if (err && (err != LFS_ERR_NOENT || strchr(path, '/') != NULL)) {
01229         return err;
01230     }
01231 
01232     if (err == LFS_ERR_NOENT) {
01233         if (!(flags & LFS_O_CREAT)) {
01234             return LFS_ERR_NOENT;
01235         }
01236 
01237         // create entry to remember name
01238         entry.d.type = LFS_TYPE_REG;
01239         entry.d.elen = sizeof(entry.d) - 4;
01240         entry.d.alen = 0;
01241         entry.d.nlen = strlen(path);
01242         entry.d.u.file.head = 0xffffffff;
01243         entry.d.u.file.size = 0;
01244         err = lfs_dir_append(lfs, &cwd, &entry, path);
01245         if (err) {
01246             return err;
01247         }
01248     } else if (entry.d.type == LFS_TYPE_DIR) {
01249         return LFS_ERR_ISDIR;
01250     } else if (flags & LFS_O_EXCL) {
01251         return LFS_ERR_EXIST;
01252     }
01253 
01254     // setup file struct
01255     file->pair[0] = cwd.pair[0];
01256     file->pair[1] = cwd.pair[1];
01257     file->poff = entry.off;
01258     file->head = entry.d.u.file.head;
01259     file->size = entry.d.u.file.size;
01260     file->flags = flags;
01261     file->pos = 0;
01262 
01263     if (flags & LFS_O_TRUNC) {
01264         if (file->size != 0) {
01265             file->flags |= LFS_F_DIRTY;
01266         }
01267         file->head = 0xffffffff;
01268         file->size = 0;
01269     }
01270 
01271     // allocate buffer if needed
01272     file->cache.block = 0xffffffff;
01273     if (lfs->cfg->file_buffer) {
01274         file->cache.buffer = lfs->cfg->file_buffer;
01275     } else if ((file->flags & 3) == LFS_O_RDONLY) {
01276         file->cache.buffer = malloc(lfs->cfg->read_size);
01277         if (!file->cache.buffer) {
01278             return LFS_ERR_NOMEM;
01279         }
01280     } else {
01281         file->cache.buffer = malloc(lfs->cfg->prog_size);
01282         if (!file->cache.buffer) {
01283             return LFS_ERR_NOMEM;
01284         }
01285     }
01286 
01287     // add to list of files
01288     file->next = lfs->files;
01289     lfs->files = file;
01290 
01291     return 0;
01292 }
01293 
01294 int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
01295     int err = lfs_file_sync(lfs, file);
01296 
01297     // remove from list of files
01298     for (lfs_file_t **p = &lfs->files; *p; p = &(*p)->next) {
01299         if (*p == file) {
01300             *p = file->next;
01301             break;
01302         }
01303     }
01304 
01305     // clean up memory
01306     if (!lfs->cfg->file_buffer) {
01307         free(file->cache.buffer);
01308     }
01309 
01310     return err;
01311 }
01312 
01313 static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
01314 relocate:
01315     LFS_DEBUG("Bad block at %ld", file->block);
01316 
01317     // just relocate what exists into new block
01318     lfs_block_t nblock;
01319     int err = lfs_alloc(lfs, &nblock);
01320     if (err) {
01321         return err;
01322     }
01323 
01324     err = lfs_bd_erase(lfs, nblock);
01325     if (err) {
01326         if (err == LFS_ERR_CORRUPT) {
01327             goto relocate;
01328         }
01329         return err;
01330     }
01331 
01332     // either read from dirty cache or disk
01333     for (lfs_off_t i = 0; i < file->off; i++) {
01334         uint8_t data;
01335         err = lfs_cache_read(lfs, &lfs->rcache, &file->cache,
01336                 file->block, i, &data, 1);
01337         if (err) {
01338             return err;
01339         }
01340 
01341         err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache,
01342                 nblock, i, &data, 1);
01343         if (err) {
01344             if (err == LFS_ERR_CORRUPT) {
01345                 goto relocate;
01346             }
01347             return err;
01348         }
01349     }
01350 
01351     // copy over new state of file
01352     memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size);
01353     file->cache.block = lfs->pcache.block;
01354     file->cache.off = lfs->pcache.off;
01355     lfs->pcache.block = 0xffffffff;
01356 
01357     file->block = nblock;
01358     return 0;
01359 }
01360 
01361 static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
01362     if (file->flags & LFS_F_READING) {
01363         // just drop read cache
01364         file->cache.block = 0xffffffff;
01365         file->flags &= ~LFS_F_READING;
01366     }
01367 
01368     if (file->flags & LFS_F_WRITING) {
01369         lfs_off_t pos = file->pos;
01370 
01371         // copy over anything after current branch
01372         lfs_file_t orig = {
01373             .head = file->head,
01374             .size = file->size,
01375             .flags = LFS_O_RDONLY,
01376             .pos = file->pos,
01377             .cache = lfs->rcache,
01378         };
01379         lfs->rcache.block = 0xffffffff;
01380 
01381         while (file->pos < file->size) {
01382             // copy over a byte at a time, leave it up to caching
01383             // to make this efficient
01384             uint8_t data;
01385             lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1);
01386             if (res < 0) {
01387                 return res;
01388             }
01389 
01390             res = lfs_file_write(lfs, file, &data, 1);
01391             if (res < 0) {
01392                 return res;
01393             }
01394 
01395             // keep our reference to the rcache in sync
01396             if (lfs->rcache.block != 0xffffffff) {
01397                 orig.cache.block = 0xffffffff;
01398                 lfs->rcache.block = 0xffffffff;
01399             }
01400         }
01401 
01402         // write out what we have
01403         while (true) {
01404             int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache);
01405             if (err) {
01406                 if (err == LFS_ERR_CORRUPT) {
01407                     goto relocate;
01408                 }
01409                 return err;
01410             }
01411 
01412             break;
01413 relocate:
01414             err = lfs_file_relocate(lfs, file);
01415             if (err) {
01416                 return err;
01417             }
01418         }
01419 
01420         // actual file updates
01421         file->head = file->block;
01422         file->size = file->pos;
01423         file->flags &= ~LFS_F_WRITING;
01424         file->flags |= LFS_F_DIRTY;
01425 
01426         file->pos = pos;
01427     }
01428 
01429     return 0;
01430 }
01431 
01432 int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
01433     int err = lfs_file_flush(lfs, file);
01434     if (err) {
01435         return err;
01436     }
01437 
01438     if ((file->flags & LFS_F_DIRTY) &&
01439             !(file->flags & LFS_F_ERRED) &&
01440             !lfs_pairisnull(file->pair)) {
01441         // update dir entry
01442         lfs_dir_t cwd;
01443         int err = lfs_dir_fetch(lfs, &cwd, file->pair);
01444         if (err) {
01445             return err;
01446         }
01447 
01448         lfs_entry_t entry = {.off = file->poff};
01449         err = lfs_bd_read(lfs, cwd.pair[0], entry.off,
01450                 &entry.d, sizeof(entry.d));
01451         if (err) {
01452             return err;
01453         }
01454 
01455         if (entry.d.type != LFS_TYPE_REG) {
01456             // sanity check valid entry
01457             return LFS_ERR_INVAL;
01458         }
01459 
01460         entry.d.u.file.head = file->head;
01461         entry.d.u.file.size = file->size;
01462 
01463         err = lfs_dir_update(lfs, &cwd, &entry, NULL);
01464         if (err) {
01465             return err;
01466         }
01467 
01468         file->flags &= ~LFS_F_DIRTY;
01469     }
01470 
01471     return 0;
01472 }
01473 
01474 lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
01475         void *buffer, lfs_size_t size) {
01476     uint8_t *data = buffer;
01477     lfs_size_t nsize = size;
01478 
01479     if ((file->flags & 3) == LFS_O_WRONLY) {
01480         return LFS_ERR_INVAL;
01481     }
01482 
01483     if (file->flags & LFS_F_WRITING) {
01484         // flush out any writes
01485         int err = lfs_file_flush(lfs, file);
01486         if (err) {
01487             return err;
01488         }
01489     }
01490 
01491     if (file->pos >= file->size) {
01492         // eof if past end
01493         return 0;
01494     }
01495 
01496     size = lfs_min(size, file->size - file->pos);
01497     nsize = size;
01498 
01499     while (nsize > 0) {
01500         // check if we need a new block
01501         if (!(file->flags & LFS_F_READING) ||
01502                 file->off == lfs->cfg->block_size) {
01503             int err = lfs_ctz_find(lfs, &file->cache, NULL,
01504                     file->head, file->size,
01505                     file->pos, &file->block, &file->off);
01506             if (err) {
01507                 return err;
01508             }
01509 
01510             file->flags |= LFS_F_READING;
01511         }
01512 
01513         // read as much as we can in current block
01514         lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
01515         int err = lfs_cache_read(lfs, &file->cache, NULL,
01516                 file->block, file->off, data, diff);
01517         if (err) {
01518             return err;
01519         }
01520 
01521         file->pos += diff;
01522         file->off += diff;
01523         data += diff;
01524         nsize -= diff;
01525     }
01526 
01527     return size;
01528 }
01529 
01530 lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
01531         const void *buffer, lfs_size_t size) {
01532     const uint8_t *data = buffer;
01533     lfs_size_t nsize = size;
01534 
01535     if ((file->flags & 3) == LFS_O_RDONLY) {
01536         return LFS_ERR_INVAL;
01537     }
01538 
01539     if (file->flags & LFS_F_READING) {
01540         // drop any reads
01541         int err = lfs_file_flush(lfs, file);
01542         if (err) {
01543             return err;
01544         }
01545     }
01546 
01547     if ((file->flags & LFS_O_APPEND) && file->pos < file->size) {
01548         file->pos = file->size;
01549     }
01550 
01551     if (!(file->flags & LFS_F_WRITING) && file->pos > file->size) {
01552         // fill with zeros
01553         lfs_off_t pos = file->pos;
01554         file->pos = file->size;
01555 
01556         while (file->pos < pos) {
01557             lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1);
01558             if (res < 0) {
01559                 return res;
01560             }
01561         }
01562     }
01563 
01564     while (nsize > 0) {
01565         // check if we need a new block
01566         if (!(file->flags & LFS_F_WRITING) ||
01567                 file->off == lfs->cfg->block_size) {
01568             if (!(file->flags & LFS_F_WRITING) && file->pos > 0) {
01569                 // find out which block we're extending from
01570                 int err = lfs_ctz_find(lfs, &file->cache, NULL,
01571                         file->head, file->size,
01572                         file->pos-1, &file->block, &file->off);
01573                 if (err) {
01574                     file->flags |= LFS_F_ERRED;
01575                     return err;
01576                 }
01577 
01578                 // mark cache as dirty since we may have read data into it
01579                 file->cache.block = 0xffffffff;
01580             }
01581 
01582             // extend file with new blocks
01583             lfs_alloc_ack(lfs);
01584             int err = lfs_ctz_extend(lfs, &lfs->rcache, &file->cache,
01585                     file->block, file->pos,
01586                     &file->block, &file->off);
01587             if (err) {
01588                 file->flags |= LFS_F_ERRED;
01589                 return err;
01590             }
01591 
01592             file->flags |= LFS_F_WRITING;
01593         }
01594 
01595         // program as much as we can in current block
01596         lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off);
01597         while (true) {
01598             int err = lfs_cache_prog(lfs, &file->cache, &lfs->rcache,
01599                     file->block, file->off, data, diff);
01600             if (err) {
01601                 if (err == LFS_ERR_CORRUPT) {
01602                     goto relocate;
01603                 }
01604                 file->flags |= LFS_F_ERRED;
01605                 return err;
01606             }
01607 
01608             break;
01609 relocate:
01610             err = lfs_file_relocate(lfs, file);
01611             if (err) {
01612                 file->flags |= LFS_F_ERRED;
01613                 return err;
01614             }
01615         }
01616 
01617         file->pos += diff;
01618         file->off += diff;
01619         data += diff;
01620         nsize -= diff;
01621 
01622         lfs_alloc_ack(lfs);
01623     }
01624 
01625     file->flags &= ~LFS_F_ERRED;
01626     return size;
01627 }
01628 
01629 lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
01630         lfs_soff_t off, int whence) {
01631     // write out everything beforehand, may be noop if rdonly
01632     int err = lfs_file_flush(lfs, file);
01633     if (err) {
01634         return err;
01635     }
01636 
01637     // update pos
01638     if (whence == LFS_SEEK_SET) {
01639         file->pos = off;
01640     } else if (whence == LFS_SEEK_CUR) {
01641         if (off < 0 && (lfs_off_t)-off > file->pos) {
01642             return LFS_ERR_INVAL;
01643         }
01644 
01645         file->pos = file->pos + off;
01646     } else if (whence == LFS_SEEK_END) {
01647         if (off < 0 && (lfs_off_t)-off > file->size) {
01648             return LFS_ERR_INVAL;
01649         }
01650 
01651         file->pos = file->size + off;
01652     }
01653 
01654     return file->pos;
01655 }
01656 
01657 lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) {
01658     return file->pos;
01659 }
01660 
01661 int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) {
01662     lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET);
01663     if (res < 0) {
01664         return res;
01665     }
01666 
01667     return 0;
01668 }
01669 
01670 lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
01671     return lfs_max(file->pos, file->size);
01672 }
01673 
01674 
01675 /// General fs oprations ///
01676 int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
01677     // check for root, can only be something like '/././../.'
01678     if (strspn(path, "/.") == strlen(path)) {
01679         memset(info, 0, sizeof(*info));
01680         info->type = LFS_TYPE_DIR;
01681         strcpy(info->name, "/");
01682         return 0;
01683     }
01684 
01685     lfs_dir_t cwd;
01686     int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
01687     if (err) {
01688         return err;
01689     }
01690 
01691     lfs_entry_t entry;
01692     err = lfs_dir_find(lfs, &cwd, &entry, &path);
01693     if (err) {
01694         return err;
01695     }
01696 
01697     memset(info, 0, sizeof(*info));
01698     info->type = entry.d.type;
01699     if (info->type == LFS_TYPE_REG) {
01700         info->size = entry.d.u.file.size;
01701     }
01702 
01703     err = lfs_bd_read(lfs, cwd.pair[0],
01704             entry.off + 4+entry.d.elen+entry.d.alen,
01705             info->name, entry.d.nlen);
01706     if (err) {
01707         return err;
01708     }
01709 
01710     return 0;
01711 }
01712 
01713 int lfs_remove(lfs_t *lfs, const char *path) {
01714     // deorphan if we haven't yet, needed at most once after poweron
01715     if (!lfs->deorphaned) {
01716         int err = lfs_deorphan(lfs);
01717         if (err) {
01718             return err;
01719         }
01720     }
01721 
01722     lfs_dir_t cwd;
01723     int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
01724     if (err) {
01725         return err;
01726     }
01727 
01728     lfs_entry_t entry;
01729     err = lfs_dir_find(lfs, &cwd, &entry, &path);
01730     if (err) {
01731         return err;
01732     }
01733 
01734     lfs_dir_t dir;
01735     if (entry.d.type == LFS_TYPE_DIR) {
01736         // must be empty before removal, checking size
01737         // without masking top bit checks for any case where
01738         // dir is not empty
01739         int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
01740         if (err) {
01741             return err;
01742         } else if (dir.d.size != sizeof(dir.d)+4) {
01743             return LFS_ERR_INVAL;
01744         }
01745     }
01746 
01747     // remove the entry
01748     err = lfs_dir_remove(lfs, &cwd, &entry);
01749     if (err) {
01750         return err;
01751     }
01752 
01753     // if we were a directory, find pred, replace tail
01754     if (entry.d.type == LFS_TYPE_DIR) {
01755         int res = lfs_pred(lfs, dir.pair, &cwd);
01756         if (res < 0) {
01757             return res;
01758         }
01759 
01760         assert(res); // must have pred
01761         cwd.d.tail[0] = dir.d.tail[0];
01762         cwd.d.tail[1] = dir.d.tail[1];
01763 
01764         int err = lfs_dir_commit(lfs, &cwd, NULL, 0);
01765         if (err) {
01766             return err;
01767         }
01768     }
01769 
01770     return 0;
01771 }
01772 
01773 int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
01774     // deorphan if we haven't yet, needed at most once after poweron
01775     if (!lfs->deorphaned) {
01776         int err = lfs_deorphan(lfs);
01777         if (err) {
01778             return err;
01779         }
01780     }
01781 
01782     // find old entry
01783     lfs_dir_t oldcwd;
01784     int err = lfs_dir_fetch(lfs, &oldcwd, lfs->root);
01785     if (err) {
01786         return err;
01787     }
01788 
01789     lfs_entry_t oldentry;
01790     err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath);
01791     if (err) {
01792         return err;
01793     }
01794 
01795     // allocate new entry
01796     lfs_dir_t newcwd;
01797     err = lfs_dir_fetch(lfs, &newcwd, lfs->root);
01798     if (err) {
01799         return err;
01800     }
01801 
01802     lfs_entry_t preventry;
01803     err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath);
01804     if (err && (err != LFS_ERR_NOENT || strchr(newpath, '/') != NULL)) {
01805         return err;
01806     }
01807 
01808     bool prevexists = (err != LFS_ERR_NOENT);
01809     bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);
01810 
01811     // must have same type
01812     if (prevexists && preventry.d.type != oldentry.d.type) {
01813         return LFS_ERR_INVAL;
01814     }
01815 
01816     lfs_dir_t dir;
01817     if (prevexists && preventry.d.type == LFS_TYPE_DIR) {
01818         // must be empty before removal, checking size
01819         // without masking top bit checks for any case where
01820         // dir is not empty
01821         int err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir);
01822         if (err) {
01823             return err;
01824         } else if (dir.d.size != sizeof(dir.d)+4) {
01825             return LFS_ERR_INVAL;
01826         }
01827     }
01828 
01829     // mark as moving
01830     oldentry.d.type |= 0x80;
01831     err = lfs_dir_update(lfs, &oldcwd, &oldentry, NULL);
01832     if (err) {
01833         return err;
01834     }
01835 
01836     // update pair if newcwd == oldcwd
01837     if (samepair) {
01838         newcwd = oldcwd;
01839     }
01840 
01841     // move to new location
01842     lfs_entry_t newentry = preventry;
01843     newentry.d = oldentry.d;
01844     newentry.d.type &= ~0x80;
01845     newentry.d.nlen = strlen(newpath);
01846 
01847     if (prevexists) {
01848         int err = lfs_dir_update(lfs, &newcwd, &newentry, newpath);
01849         if (err) {
01850             return err;
01851         }
01852     } else {
01853         int err = lfs_dir_append(lfs, &newcwd, &newentry, newpath);
01854         if (err) {
01855             return err;
01856         }
01857     }
01858 
01859     // update pair if newcwd == oldcwd
01860     if (samepair) {
01861         oldcwd = newcwd;
01862     }
01863 
01864     // remove old entry
01865     err = lfs_dir_remove(lfs, &oldcwd, &oldentry);
01866     if (err) {
01867         return err;
01868     }
01869 
01870     // if we were a directory, find pred, replace tail
01871     if (prevexists && preventry.d.type == LFS_TYPE_DIR) {
01872         int res = lfs_pred(lfs, dir.pair, &newcwd);
01873         if (res < 0) {
01874             return res;
01875         }
01876 
01877         assert(res); // must have pred
01878         newcwd.d.tail[0] = dir.d.tail[0];
01879         newcwd.d.tail[1] = dir.d.tail[1];
01880 
01881         int err = lfs_dir_commit(lfs, &newcwd, NULL, 0);
01882         if (err) {
01883             return err;
01884         }
01885     }
01886 
01887     return 0;
01888 }
01889 
01890 
01891 /// Filesystem operations ///
01892 static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
01893     lfs->cfg = cfg;
01894 
01895     // setup read cache
01896     lfs->rcache.block = 0xffffffff;
01897     if (lfs->cfg->read_buffer) {
01898         lfs->rcache.buffer = lfs->cfg->read_buffer;
01899     } else {
01900         lfs->rcache.buffer = malloc(lfs->cfg->read_size);
01901         if (!lfs->rcache.buffer) {
01902             return LFS_ERR_NOMEM;
01903         }
01904     }
01905 
01906     // setup program cache
01907     lfs->pcache.block = 0xffffffff;
01908     if (lfs->cfg->prog_buffer) {
01909         lfs->pcache.buffer = lfs->cfg->prog_buffer;
01910     } else {
01911         lfs->pcache.buffer = malloc(lfs->cfg->prog_size);
01912         if (!lfs->pcache.buffer) {
01913             return LFS_ERR_NOMEM;
01914         }
01915     }
01916 
01917     // setup lookahead, round down to nearest 32-bits
01918     assert(lfs->cfg->lookahead % 32 == 0);
01919     assert(lfs->cfg->lookahead > 0);
01920     if (lfs->cfg->lookahead_buffer) {
01921         lfs->free.buffer = lfs->cfg->lookahead_buffer;
01922     } else {
01923         lfs->free.buffer = malloc(lfs->cfg->lookahead/8);
01924         if (!lfs->free.buffer) {
01925             return LFS_ERR_NOMEM;
01926         }
01927     }
01928 
01929     // check that the block size is large enough to fit ctz pointers
01930     assert(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4))
01931             <= lfs->cfg->block_size);
01932 
01933     // setup default state
01934     lfs->root[0] = 0xffffffff;
01935     lfs->root[1] = 0xffffffff;
01936     lfs->files = NULL;
01937     lfs->dirs = NULL;
01938     lfs->deorphaned = false;
01939 
01940     return 0;
01941 }
01942 
01943 static int lfs_deinit(lfs_t *lfs) {
01944     // free allocated memory
01945     if (!lfs->cfg->read_buffer) {
01946         free(lfs->rcache.buffer);
01947     }
01948 
01949     if (!lfs->cfg->prog_buffer) {
01950         free(lfs->pcache.buffer);
01951     }
01952 
01953     if (!lfs->cfg->lookahead_buffer) {
01954         free(lfs->free.buffer);
01955     }
01956 
01957     return 0;
01958 }
01959 
01960 int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
01961     int err = lfs_init(lfs, cfg);
01962     if (err) {
01963         return err;
01964     }
01965 
01966     // create free lookahead
01967     memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8);
01968     lfs->free.begin = 0;
01969     lfs->free.off = 0;
01970     lfs->free.end = lfs->free.begin + lfs->free.off + lfs->cfg->block_count;
01971 
01972     // create superblock dir
01973     lfs_alloc_ack(lfs);
01974     lfs_dir_t superdir;
01975     err = lfs_dir_alloc(lfs, &superdir);
01976     if (err) {
01977         return err;
01978     }
01979 
01980     // write root directory
01981     lfs_dir_t root;
01982     err = lfs_dir_alloc(lfs, &root);
01983     if (err) {
01984         return err;
01985     }
01986 
01987     err = lfs_dir_commit(lfs, &root, NULL, 0);
01988     if (err) {
01989         return err;
01990     }
01991 
01992     lfs->root[0] = root.pair[0];
01993     lfs->root[1] = root.pair[1];
01994 
01995     // write superblocks
01996     lfs_superblock_t superblock = {
01997         .off = sizeof(superdir.d),
01998         .d.type = LFS_TYPE_SUPERBLOCK,
01999         .d.elen = sizeof(superblock.d) - sizeof(superblock.d.magic) - 4,
02000         .d.nlen = sizeof(superblock.d.magic),
02001         .d.version = 0x00010001,
02002         .d.magic = {"littlefs"},
02003         .d.block_size  = lfs->cfg->block_size,
02004         .d.block_count = lfs->cfg->block_count,
02005         .d.root = {lfs->root[0], lfs->root[1]},
02006     };
02007     superdir.d.tail[0] = root.pair[0];
02008     superdir.d.tail[1] = root.pair[1];
02009     superdir.d.size = sizeof(superdir.d) + sizeof(superblock.d) + 4;
02010 
02011     // write both pairs to be safe
02012     bool valid = false;
02013     for (int i = 0; i < 2; i++) {
02014         int err = lfs_dir_commit(lfs, &superdir, (struct lfs_region[]){
02015                 {sizeof(superdir.d), sizeof(superblock.d),
02016                  &superblock.d, sizeof(superblock.d)}
02017             }, 1);
02018         if (err && err != LFS_ERR_CORRUPT) {
02019             return err;
02020         }
02021 
02022         valid = valid || !err;
02023     }
02024 
02025     if (!valid) {
02026         return LFS_ERR_CORRUPT;
02027     }
02028 
02029     // sanity check that fetch works
02030     err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1});
02031     if (err) {
02032         return err;
02033     }
02034 
02035     lfs_alloc_ack(lfs);
02036     return lfs_deinit(lfs);
02037 }
02038 
02039 int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
02040     int err = lfs_init(lfs, cfg);
02041     if (err) {
02042         return err;
02043     }
02044 
02045     // setup free lookahead, rewind so first allocation triggers a scan
02046     lfs->free.begin = -lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
02047     lfs->free.off = -lfs->free.begin;
02048     lfs->free.end = lfs->free.begin + lfs->free.off + lfs->cfg->block_count;
02049 
02050     // load superblock
02051     lfs_dir_t dir;
02052     lfs_superblock_t superblock;
02053     err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1});
02054     if (err && err != LFS_ERR_CORRUPT) {
02055         return err;
02056     }
02057 
02058     if (!err) {
02059         int err = lfs_bd_read(lfs, dir.pair[0], sizeof(dir.d),
02060                 &superblock.d, sizeof(superblock.d));
02061         if (err) {
02062             return err;
02063         }
02064 
02065         lfs->root[0] = superblock.d.root[0];
02066         lfs->root[1] = superblock.d.root[1];
02067     }
02068 
02069     if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) {
02070         LFS_ERROR("Invalid superblock at %ld %ld", dir.pair[0], dir.pair[1]);
02071         return LFS_ERR_CORRUPT;
02072     }
02073 
02074     if (superblock.d.version > (0x00010001 | 0x0000ffff)) {
02075         LFS_ERROR("Invalid version %ld.%ld",
02076                 0xffff & (superblock.d.version >> 16),
02077                 0xffff & (superblock.d.version >> 0));
02078         return LFS_ERR_INVAL;
02079     }
02080 
02081     return 0;
02082 }
02083 
02084 int lfs_unmount(lfs_t *lfs) {
02085     return lfs_deinit(lfs);
02086 }
02087 
02088 
02089 /// Littlefs specific operations ///
02090 int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
02091     if (lfs_pairisnull(lfs->root)) {
02092         return 0;
02093     }
02094 
02095     // iterate over metadata pairs
02096     lfs_dir_t dir;
02097     lfs_entry_t entry;
02098     lfs_block_t cwd[2] = {0, 1};
02099 
02100     while (true) {
02101         for (int i = 0; i < 2; i++) {
02102             int err = cb(data, cwd[i]);
02103             if (err) {
02104                 return err;
02105             }
02106         }
02107 
02108         int err = lfs_dir_fetch(lfs, &dir, cwd);
02109         if (err) {
02110             return err;
02111         }
02112 
02113         // iterate over contents
02114         while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) {
02115             int err = lfs_bd_read(lfs, dir.pair[0], dir.off,
02116                     &entry.d, sizeof(entry.d));
02117             if (err) {
02118                 return err;
02119             }
02120 
02121             dir.off += lfs_entry_size(&entry);
02122             if ((0x70 & entry.d.type) == (0x70 & LFS_TYPE_REG)) {
02123                 int err = lfs_ctz_traverse(lfs, &lfs->rcache, NULL,
02124                         entry.d.u.file.head, entry.d.u.file.size, cb, data);
02125                 if (err) {
02126                     return err;
02127                 }
02128             }
02129         }
02130 
02131         cwd[0] = dir.d.tail[0];
02132         cwd[1] = dir.d.tail[1];
02133 
02134         if (lfs_pairisnull(cwd)) {
02135             break;
02136         }
02137     }
02138 
02139     // iterate over any open files
02140     for (lfs_file_t *f = lfs->files; f; f = f->next) {
02141         if (f->flags & LFS_F_DIRTY) {
02142             int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache,
02143                     f->head, f->size, cb, data);
02144             if (err) {
02145                 return err;
02146             }
02147         }
02148 
02149         if (f->flags & LFS_F_WRITING) {
02150             int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache,
02151                     f->block, f->pos, cb, data);
02152             if (err) {
02153                 return err;
02154             }
02155         }
02156     }
02157     
02158     return 0;
02159 }
02160 
02161 static int lfs_pred(lfs_t *lfs, const lfs_block_t dir[2], lfs_dir_t *pdir) {
02162     if (lfs_pairisnull(lfs->root)) {
02163         return 0;
02164     }
02165 
02166     // iterate over all directory directory entries
02167     int err = lfs_dir_fetch(lfs, pdir, (const lfs_block_t[2]){0, 1});
02168     if (err) {
02169         return err;
02170     }
02171 
02172     while (!lfs_pairisnull(pdir->d.tail)) {
02173         if (lfs_paircmp(pdir->d.tail, dir) == 0) {
02174             return true;
02175         }
02176 
02177         int err = lfs_dir_fetch(lfs, pdir, pdir->d.tail);
02178         if (err) {
02179             return err;
02180         }
02181     }
02182 
02183     return false;
02184 }
02185 
02186 static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2],
02187         lfs_dir_t *parent, lfs_entry_t *entry) {
02188     if (lfs_pairisnull(lfs->root)) {
02189         return 0;
02190     }
02191     
02192     parent->d.tail[0] = 0;
02193     parent->d.tail[1] = 1;
02194 
02195     // iterate over all directory directory entries
02196     while (!lfs_pairisnull(parent->d.tail)) {
02197         int err = lfs_dir_fetch(lfs, parent, parent->d.tail);
02198         if (err) {
02199             return err;
02200         }
02201 
02202         while (true) {
02203             int err = lfs_dir_next(lfs, parent, entry);
02204             if (err && err != LFS_ERR_NOENT) {
02205                 return err;
02206             }
02207 
02208             if (err == LFS_ERR_NOENT) {
02209                 break;
02210             }
02211 
02212             if (((0x70 & entry->d.type) == (0x70 & LFS_TYPE_DIR)) &&
02213                  lfs_paircmp(entry->d.u.dir, dir) == 0) {
02214                 return true;
02215             }
02216         }
02217     }
02218 
02219     return false;
02220 }
02221 
02222 static int lfs_moved(lfs_t *lfs, const void *e) {
02223     if (lfs_pairisnull(lfs->root)) {
02224         return 0;
02225     }
02226 
02227     // skip superblock
02228     lfs_dir_t cwd;
02229     int err = lfs_dir_fetch(lfs, &cwd, (const lfs_block_t[2]){0, 1});
02230     if (err) {
02231         return err;
02232     }
02233 
02234     // iterate over all directory directory entries
02235     lfs_entry_t entry;
02236     while (!lfs_pairisnull(cwd.d.tail)) {
02237         int err = lfs_dir_fetch(lfs, &cwd, cwd.d.tail);
02238         if (err) {
02239             return err;
02240         }
02241 
02242         while (true) {
02243             int err = lfs_dir_next(lfs, &cwd, &entry);
02244             if (err && err != LFS_ERR_NOENT) {
02245                 return err;
02246             }
02247 
02248             if (err == LFS_ERR_NOENT) {
02249                 break;
02250             }
02251 
02252             if (!(0x80 & entry.d.type) && 
02253                  memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) {
02254                 return true;
02255             }
02256         }
02257     }
02258 
02259     return false;
02260 }
02261 
02262 static int lfs_relocate(lfs_t *lfs,
02263         const lfs_block_t oldpair[2], const lfs_block_t newpair[2]) {
02264     // find parent
02265     lfs_dir_t parent;
02266     lfs_entry_t entry;
02267     int res = lfs_parent(lfs, oldpair, &parent, &entry);
02268     if (res < 0) {
02269         return res;
02270     }
02271 
02272     if (res) {
02273         // update disk, this creates a desync
02274         entry.d.u.dir[0] = newpair[0];
02275         entry.d.u.dir[1] = newpair[1];
02276 
02277         int err = lfs_dir_update(lfs, &parent, &entry, NULL);
02278         if (err) {
02279             return err;
02280         }
02281 
02282         // update internal root
02283         if (lfs_paircmp(oldpair, lfs->root) == 0) {
02284             LFS_DEBUG("Relocating root %ld %ld", newpair[0], newpair[1]);
02285             lfs->root[0] = newpair[0];
02286             lfs->root[1] = newpair[1];
02287         }
02288 
02289         // clean up bad block, which should now be a desync
02290         return lfs_deorphan(lfs);
02291     }
02292 
02293     // find pred
02294     res = lfs_pred(lfs, oldpair, &parent);
02295     if (res < 0) {
02296         return res;
02297     }
02298 
02299     if (res) {
02300         // just replace bad pair, no desync can occur
02301         parent.d.tail[0] = newpair[0];
02302         parent.d.tail[1] = newpair[1];
02303 
02304         return lfs_dir_commit(lfs, &parent, NULL, 0);
02305     }
02306 
02307     // couldn't find dir, must be new
02308     return 0;
02309 }
02310 
02311 int lfs_deorphan(lfs_t *lfs) {
02312     lfs->deorphaned = true;
02313 
02314     if (lfs_pairisnull(lfs->root)) {
02315         return 0;
02316     }
02317 
02318     lfs_dir_t pdir = {.d.size = 0x80000000};
02319     lfs_dir_t cwd = {.d.tail[0] = 0, .d.tail[1] = 1};
02320 
02321     // iterate over all directory directory entries
02322     while (!lfs_pairisnull(cwd.d.tail)) {
02323         int err = lfs_dir_fetch(lfs, &cwd, cwd.d.tail);
02324         if (err) {
02325             return err;
02326         }
02327 
02328         // check head blocks for orphans
02329         if (!(0x80000000 & pdir.d.size)) {
02330             // check if we have a parent
02331             lfs_dir_t parent;
02332             lfs_entry_t entry;
02333             int res = lfs_parent(lfs, pdir.d.tail, &parent, &entry);
02334             if (res < 0) {
02335                 return res;
02336             }
02337 
02338             if (!res) {
02339                 // we are an orphan
02340                 LFS_DEBUG("Found orphan %ld %ld",
02341                         pdir.d.tail[0], pdir.d.tail[1]);
02342 
02343                 pdir.d.tail[0] = cwd.d.tail[0];
02344                 pdir.d.tail[1] = cwd.d.tail[1];
02345 
02346                 err = lfs_dir_commit(lfs, &pdir, NULL, 0);
02347                 if (err) {
02348                     return err;
02349                 }
02350 
02351                 break;
02352             }
02353 
02354             if (!lfs_pairsync(entry.d.u.dir, pdir.d.tail)) {
02355                 // we have desynced
02356                 LFS_DEBUG("Found desync %ld %ld",
02357                         entry.d.u.dir[0], entry.d.u.dir[1]);
02358 
02359                 pdir.d.tail[0] = entry.d.u.dir[0];
02360                 pdir.d.tail[1] = entry.d.u.dir[1];
02361 
02362                 err = lfs_dir_commit(lfs, &pdir, NULL, 0);
02363                 if (err) {
02364                     return err;
02365                 }
02366 
02367                 break;
02368             }
02369         }
02370 
02371         // check entries for moves
02372         lfs_entry_t entry;
02373         while (true) {
02374             int err = lfs_dir_next(lfs, &cwd, &entry);
02375             if (err && err != LFS_ERR_NOENT) {
02376                 return err;
02377             }
02378 
02379             if (err == LFS_ERR_NOENT) {
02380                 break;
02381             }
02382 
02383             // found moved entry
02384             if (entry.d.type & 0x80) {
02385                 int moved = lfs_moved(lfs, &entry.d.u);
02386                 if (moved < 0) {
02387                     return moved;
02388                 }
02389 
02390                 if (moved) {
02391                     LFS_DEBUG("Found move %ld %ld",
02392                             entry.d.u.dir[0], entry.d.u.dir[1]);
02393                     int err = lfs_dir_remove(lfs, &cwd, &entry);
02394                     if (err) {
02395                         return err;
02396                     }
02397                 } else {
02398                     LFS_DEBUG("Found partial move %ld %ld",
02399                             entry.d.u.dir[0], entry.d.u.dir[1]);
02400                     entry.d.type &= ~0x80;
02401                     int err = lfs_dir_update(lfs, &cwd, &entry, NULL);
02402                     if (err) {
02403                         return err;
02404                     }
02405                 }
02406             }
02407         }
02408 
02409         memcpy(&pdir, &cwd, sizeof(pdir));
02410     }
02411 
02412     return 0;
02413 }
02414