blob: ea50b746e0afebd37a8f4d56f3df2e0f51999a3d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_NFFS_
#define H_NFFS_
#include <stddef.h>
#include <inttypes.h>
#include <nffs/config.h>
#include <nffs/queue.h>
#if __ZEPHYR__
#include <zephyr/types.h>
#include <stats.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* File access flags.
*/
#define FS_ACCESS_READ 0x01
#define FS_ACCESS_WRITE 0x02
#define FS_ACCESS_APPEND 0x04
#define FS_ACCESS_TRUNCATE 0x08
/*
* File access return codes.
*/
#define FS_EOK 0 /* Success */
#define FS_ECORRUPT 1 /* File system corrupt */
#define FS_EHW 2 /* Error accessing storage medium */
#define FS_EOFFSET 3 /* Invalid offset */
#define FS_EINVAL 4 /* Invalid argument */
#define FS_ENOMEM 5 /* Insufficient memory */
#define FS_ENOENT 6 /* No such file or directory */
#define FS_EEMPTY 7 /* Specified region is empty (internal only) */
#define FS_EFULL 8 /* Disk full */
#define FS_EUNEXP 9 /* Disk contains unexpected metadata */
#define FS_EOS 10 /* OS error */
#define FS_EEXIST 11 /* File or directory already exists */
#define FS_EACCESS 12 /* Operation prohibited by file open mode */
#define FS_EUNINIT 13 /* File system not initialized */
#define NFFS_FILENAME_MAX_LEN 256 /* Does not require null terminator. */
#define NFFS_HASH_SIZE 256
#define NFFS_ID_DIR_MIN 0
#define NFFS_ID_DIR_MAX 0x10000000
#define NFFS_ID_FILE_MIN 0x10000000
#define NFFS_ID_FILE_MAX 0x80000000
#define NFFS_ID_BLOCK_MIN 0x80000000
#define NFFS_ID_BLOCK_MAX 0xffffffff
#define NFFS_ID_ROOT_DIR 0
#define NFFS_ID_NONE 0xffffffff
#define NFFS_HASH_ENTRY_NONE 0xffffffff
#define NFFS_AREA_MAGIC0 0xb98a31e2
#define NFFS_AREA_MAGIC1 0x7fb0428c
#define NFFS_AREA_MAGIC2 0xace08253
#define NFFS_AREA_MAGIC3 0xb185fc8e
#define NFFS_BLOCK_MAGIC 0x53ba23b9
#define NFFS_INODE_MAGIC 0x925f8bc0
#define NFFS_AREA_ID_NONE 0xff
#define NFFS_AREA_VER_0 0
#define NFFS_AREA_VER_1 1
#define NFFS_AREA_VER NFFS_AREA_VER_1
#define NFFS_AREA_OFFSET_ID 23
#define NFFS_SHORT_FILENAME_LEN 3
#define NFFS_BLOCK_MAX_DATA_SZ_MAX NFFS_CONFIG_MAX_BLOCK_SIZE
#define NFFS_DETECT_FAIL_IGNORE 1
#define NFFS_DETECT_FAIL_FORMAT 2
struct nffs_flash_desc {
uint8_t id;
uint32_t sector_count;
uint32_t area_offset;
uint32_t area_size;
};
struct nffs_area_desc {
uint32_t nad_offset; /* Flash offset of start of area. */
uint32_t nad_length; /* Size of area, in bytes. */
uint8_t nad_flash_id; /* Logical flash id */
};
/** On-disk representation of an area header. */
struct nffs_disk_area {
uint32_t nda_magic[4]; /* NFFS_AREA_MAGIC{0,1,2,3} */
uint32_t nda_length; /* Total size of area, in bytes. */
uint8_t nda_ver; /* Current nffs version: 0 */
uint8_t nda_gc_seq; /* Garbage collection count. */
uint8_t reserved8;
uint8_t nda_id; /* 0xff if scratch area. */
};
/** On-disk representation of an inode (file or directory). */
struct nffs_disk_inode {
uint32_t ndi_id; /* Unique object ID. */
uint32_t ndi_parent_id; /* Object ID of parent directory inode. */
uint32_t ndi_lastblock_id; /* Object ID of parent directory inode. */
uint16_t ndi_seq; /* Sequence number; greater supersedes
lesser. */
uint16_t reserved16;
uint8_t ndi_flags; /* flags */
uint8_t ndi_filename_len; /* Length of filename, in bytes. */
uint16_t ndi_crc16; /* Covers rest of header and filename. */
/* Followed by filename. */
};
#define NFFS_DISK_INODE_OFFSET_CRC 18
/** On-disk representation of a data block. */
struct nffs_disk_block {
uint32_t ndb_id; /* Unique object ID. */
uint32_t ndb_inode_id; /* Object ID of owning inode. */
uint32_t ndb_prev_id; /* Object ID of previous block in file;
NFFS_ID_NONE if this is the first block. */
uint16_t ndb_seq; /* Sequence number; greater supersedes lesser. */
uint16_t reserved16;
uint16_t ndb_data_len; /* Length of data contents, in bytes. */
uint16_t ndb_crc16; /* Covers rest of header and data. */
/* Followed by 'ndb_data_len' bytes of data. */
};
#define NFFS_DISK_BLOCK_OFFSET_CRC 18
/**
* What gets stored in the hash table. Each entry represents a data block or
* an inode.
*/
struct nffs_hash_entry {
SLIST_ENTRY(nffs_hash_entry) nhe_next;
uint32_t nhe_id; /* 0 - 0x7fffffff if inode; else if block. */
uint32_t nhe_flash_loc; /* Upper-byte = area idx; rest = area offset. */
};
SLIST_HEAD(nffs_hash_list, nffs_hash_entry);
SLIST_HEAD(nffs_inode_list, nffs_inode_entry);
/** Each inode hash entry is actually one of these. */
struct nffs_inode_entry {
struct nffs_hash_entry nie_hash_entry;
SLIST_ENTRY(nffs_inode_entry) nie_sibling_next;
union {
struct nffs_inode_list nie_child_list; /* If directory */
struct nffs_hash_entry *nie_last_block_entry; /* If file */
uint32_t nie_lastblock_id;
};
uint8_t nie_refcnt;
uint8_t nie_flags;
uint8_t nie_blkcnt;
uint8_t reserved8;
};
#define NFFS_INODE_FLAG_FREE 0x00
#define NFFS_INODE_FLAG_DUMMY 0x01 /* inode is a dummy */
#define NFFS_INODE_FLAG_DUMMYPARENT 0x02 /* parent not in cache */
#define NFFS_INODE_FLAG_DUMMYLSTBLK 0x04 /* lastblock not in cache */
#define NFFS_INODE_FLAG_DUMMYINOBLK 0x08 /* dummy inode for blk */
#define NFFS_INODE_FLAG_OBSOLETE 0x10 /* always replace if same ID */
#define NFFS_INODE_FLAG_INTREE 0x20 /* in directory structure */
#define NFFS_INODE_FLAG_INHASH 0x40 /* in hash table */
#define NFFS_INODE_FLAG_DELETED 0x80 /* inode deleted */
#define nie_id nie_hash_entry.nhe_id
#define nie_flash_loc nie_hash_entry.nhe_flash_loc
/** Full inode representation; not stored permanently RAM. */
struct nffs_inode {
struct nffs_inode_entry *ni_inode_entry; /* Points to real inode entry. */
uint32_t ni_seq; /* Sequence number; greater
supersedes lesser. */
struct nffs_inode_entry *ni_parent; /* Points to parent directory. */
uint8_t ni_filename_len; /* # chars in filename. */
uint8_t ni_filename[NFFS_SHORT_FILENAME_LEN]; /* First 3 bytes. */
};
/** Full data block representation; not stored permanently RAM. */
struct nffs_block {
struct nffs_hash_entry *nb_hash_entry; /* Points to real block entry. */
uint32_t nb_seq; /* Sequence number; greater
supersedes lesser. */
struct nffs_inode_entry *nb_inode_entry; /* Owning inode. */
struct nffs_hash_entry *nb_prev; /* Previous block in file. */
uint16_t nb_data_len; /* # of data bytes in block. */
uint16_t reserved16;
};
struct nffs_file {
#if !__ZEPHYR__
struct fs_ops *fops;
#endif
struct nffs_inode_entry *nf_inode_entry;
uint32_t nf_offset;
uint8_t nf_access_flags;
};
struct nffs_area {
uint32_t na_offset;
uint32_t na_length;
uint32_t na_cur;
uint16_t na_id;
uint8_t na_gc_seq;
uint8_t na_flash_id;
uint32_t na_obsolete; /* deleted bytecount */
};
struct nffs_disk_object {
int ndo_type;
uint8_t ndo_area_idx;
uint32_t ndo_offset;
union {
struct nffs_disk_inode ndo_disk_inode;
struct nffs_disk_block ndo_disk_block;
} ndo_un_obj;
};
#define ndo_disk_inode ndo_un_obj.ndo_disk_inode
#define ndo_disk_block ndo_un_obj.ndo_disk_block
struct nffs_seek_info {
struct nffs_block nsi_last_block;
uint32_t nsi_block_file_off;
uint32_t nsi_file_len;
};
#define NFFS_OBJECT_TYPE_INODE 1
#define NFFS_OBJECT_TYPE_BLOCK 2
#define NFFS_PATH_TOKEN_NONE 0
#define NFFS_PATH_TOKEN_BRANCH 1
#define NFFS_PATH_TOKEN_LEAF 2
struct nffs_path_parser {
int npp_token_type;
const char *npp_path;
const char *npp_token;
int npp_token_len;
int npp_off;
};
/** Represents a single cached data block. */
struct nffs_cache_block {
TAILQ_ENTRY(nffs_cache_block) ncb_link; /* Next / prev cached block. */
struct nffs_block ncb_block; /* Full data block. */
uint32_t ncb_file_offset; /* File offset of this block. */
};
TAILQ_HEAD(nffs_cache_block_list, nffs_cache_block);
/** Represents a single cached file inode. */
struct nffs_cache_inode {
TAILQ_ENTRY(nffs_cache_inode) nci_link; /* Sorted; LRU at tail. */
struct nffs_inode nci_inode; /* Full inode. */
struct nffs_cache_block_list nci_block_list; /* List of cached blocks. */
uint32_t nci_file_size; /* Total file size. */
};
struct nffs_dirent {
#if !__ZEPHYR__
struct fs_ops *fops;
#endif
struct nffs_inode_entry *nde_inode_entry;
};
struct nffs_dir {
#if !__ZEPHYR__
struct fs_ops *fops;
#endif
struct nffs_inode_entry *nd_parent_inode_entry;
struct nffs_dirent nd_dirent;
};
#ifdef STATS_SECT_START
/* Mynewt team can enable statistic once they
* start building this codebase.
*/
STATS_SECT_START(nffs_stats)
STATS_SECT_ENTRY(nffs_hashcnt_ins)
STATS_SECT_ENTRY(nffs_hashcnt_rm)
STATS_SECT_ENTRY(nffs_object_count)
STATS_SECT_ENTRY(nffs_iocnt_read)
STATS_SECT_ENTRY(nffs_iocnt_write)
STATS_SECT_ENTRY(nffs_gccnt)
STATS_SECT_ENTRY(nffs_readcnt_data)
STATS_SECT_ENTRY(nffs_readcnt_block)
STATS_SECT_ENTRY(nffs_readcnt_crc)
STATS_SECT_ENTRY(nffs_readcnt_copy)
STATS_SECT_ENTRY(nffs_readcnt_format)
STATS_SECT_ENTRY(nffs_readcnt_gccollate)
STATS_SECT_ENTRY(nffs_readcnt_inode)
STATS_SECT_ENTRY(nffs_readcnt_inodeent)
STATS_SECT_ENTRY(nffs_readcnt_rename)
STATS_SECT_ENTRY(nffs_readcnt_update)
STATS_SECT_ENTRY(nffs_readcnt_filename)
STATS_SECT_ENTRY(nffs_readcnt_object)
STATS_SECT_ENTRY(nffs_readcnt_detect)
STATS_SECT_END;
extern STATS_SECT_DECL(nffs_stats) nffs_stats;
#else
#define STATS_INC(sectvarname, var)
#endif
extern void *nffs_file_mem;
extern void *nffs_block_entry_mem;
extern void *nffs_inode_mem;
extern void *nffs_cache_inode_mem;
extern void *nffs_cache_block_mem;
extern void *nffs_dir_mem;
extern uint32_t nffs_hash_next_file_id;
extern uint32_t nffs_hash_next_dir_id;
extern uint32_t nffs_hash_next_block_id;
#if NFFS_CONFIG_USE_HEAP
struct nffs_area *nffs_areas;
#else
extern struct nffs_area nffs_areas[NFFS_CONFIG_MAX_AREAS];
#endif
extern uint8_t nffs_num_areas;
extern uint8_t nffs_scratch_area_idx;
extern uint16_t nffs_block_max_data_sz;
extern unsigned int nffs_gc_count;
extern struct nffs_area_desc *nffs_current_area_descs;
#define NFFS_FLASH_BUF_SZ 256
extern uint8_t nffs_flash_buf[NFFS_FLASH_BUF_SZ];
extern struct nffs_hash_list *nffs_hash;
extern struct nffs_inode_entry *nffs_root_dir;
extern struct nffs_inode_entry *nffs_lost_found_dir;
extern struct log nffs_log;
/* @area */
int nffs_area_magic_is_set(const struct nffs_disk_area *disk_area);
int nffs_area_is_scratch(const struct nffs_disk_area *disk_area);
int nffs_area_is_current_version(const struct nffs_disk_area *disk_area);
void nffs_area_to_disk(const struct nffs_area *area,
struct nffs_disk_area *out_disk_area);
uint32_t nffs_area_free_space(const struct nffs_area *area);
int nffs_area_find_corrupt_scratch(uint16_t *out_good_idx,
uint16_t *out_bad_idx);
/* @block */
struct nffs_hash_entry *nffs_block_entry_alloc(void);
void nffs_block_entry_free(struct nffs_hash_entry *entry);
int nffs_block_entry_reserve(struct nffs_hash_entry **out_block_entry);
int nffs_block_read_disk(uint8_t area_idx, uint32_t area_offset,
struct nffs_disk_block *out_disk_block);
int nffs_block_write_disk(const struct nffs_disk_block *disk_block,
const void *data,
uint8_t *out_area_idx, uint32_t *out_area_offset);
int nffs_block_delete_from_ram(struct nffs_hash_entry *entry);
void nffs_block_delete_list_from_ram(struct nffs_block *first,
struct nffs_block *last);
void nffs_block_delete_list_from_disk(const struct nffs_block *first,
const struct nffs_block *last);
void nffs_block_to_disk(const struct nffs_block *block,
struct nffs_disk_block *out_disk_block);
int nffs_block_find_predecessor(struct nffs_hash_entry *start,
uint32_t sought_id);
int nffs_block_from_hash_entry_no_ptrs(struct nffs_block *out_block,
struct nffs_hash_entry *entry);
int nffs_block_from_hash_entry(struct nffs_block *out_block,
struct nffs_hash_entry *entry);
int nffs_block_read_data(const struct nffs_block *block, uint16_t offset,
uint16_t length, void *dst);
int nffs_block_is_dummy(struct nffs_hash_entry *entry);
/* @cache */
void nffs_cache_inode_delete(const struct nffs_inode_entry *inode_entry);
int nffs_cache_inode_ensure(struct nffs_cache_inode **out_entry,
struct nffs_inode_entry *inode_entry);
int nffs_cache_inode_refresh(void);
void nffs_cache_inode_range(const struct nffs_cache_inode *cache_inode,
uint32_t *out_start, uint32_t *out_end);
int nffs_cache_seek(struct nffs_cache_inode *cache_inode, uint32_t to,
struct nffs_cache_block **out_cache_block);
void nffs_cache_clear(void);
/* @crc */
int nffs_crc_flash(uint16_t initial_crc, uint8_t area_idx,
uint32_t area_offset, uint32_t len, uint16_t *out_crc);
uint16_t nffs_crc_disk_block_hdr(const struct nffs_disk_block *disk_block);
int nffs_crc_disk_block_validate(const struct nffs_disk_block *disk_block,
uint8_t area_idx, uint32_t area_offset);
void nffs_crc_disk_block_fill(struct nffs_disk_block *disk_block,
const void *data);
int nffs_crc_disk_inode_validate(const struct nffs_disk_inode *disk_inode,
uint8_t area_idx, uint32_t area_offset);
void nffs_crc_disk_inode_fill(struct nffs_disk_inode *disk_inode,
const char *filename);
/* @config */
void nffs_config_init(void);
/* @dir */
int nffs_dir_open(const char *path, struct nffs_dir **out_dir);
int nffs_dir_read(struct nffs_dir *dir, struct nffs_dirent **out_dirent);
int nffs_dir_close(struct nffs_dir *dir);
/* @file */
int nffs_file_open(struct nffs_file **out_file, const char *filename,
uint8_t access_flags);
int nffs_file_seek(struct nffs_file *file, uint32_t offset);
int nffs_file_read(struct nffs_file *file, uint32_t len, void *out_data,
uint32_t *out_len);
int nffs_file_close(struct nffs_file *file);
int nffs_file_new(struct nffs_inode_entry *parent, const char *filename,
uint8_t filename_len, int is_dir,
struct nffs_inode_entry **out_inode_entry);
/* @format */
int nffs_format_area(uint8_t area_idx, int is_scratch);
int nffs_format_from_scratch_area(uint8_t area_idx, uint8_t area_id);
int nffs_format_full(const struct nffs_area_desc *area_descs);
/* @gc */
int nffs_gc(uint8_t *out_area_idx);
int nffs_gc_until(uint32_t space, uint8_t *out_area_idx);
/* @flash */
struct nffs_area *nffs_flash_find_area(uint16_t logical_id);
int nffs_flash_read(uint8_t area_idx, uint32_t offset,
void *data, uint32_t len);
int nffs_flash_write(uint8_t area_idx, uint32_t offset,
const void *data, uint32_t len);
int nffs_flash_copy(uint8_t area_id_from, uint32_t offset_from,
uint8_t area_id_to, uint32_t offset_to,
uint32_t len);
uint32_t nffs_flash_loc(uint8_t area_idx, uint32_t offset);
void nffs_flash_loc_expand(uint32_t flash_loc, uint8_t *out_area_idx,
uint32_t *out_area_offset);
/* @hash */
int nffs_hash_id_is_dir(uint32_t id);
int nffs_hash_id_is_file(uint32_t id);
int nffs_hash_id_is_inode(uint32_t id);
int nffs_hash_id_is_block(uint32_t id);
struct nffs_hash_entry *nffs_hash_find(uint32_t id);
struct nffs_inode_entry *nffs_hash_find_inode(uint32_t id);
struct nffs_hash_entry *nffs_hash_find_block(uint32_t id);
void nffs_hash_insert(struct nffs_hash_entry *entry);
void nffs_hash_remove(struct nffs_hash_entry *entry);
int nffs_hash_init(void);
int nffs_hash_entry_is_dummy(struct nffs_hash_entry *he);
int nffs_hash_id_is_dummy(uint32_t id);
/* @inode */
struct nffs_inode_entry *nffs_inode_entry_alloc(void);
void nffs_inode_entry_free(struct nffs_inode_entry *inode_entry);
int nffs_inode_entry_reserve(struct nffs_inode_entry **out_inode_entry);
int nffs_inode_calc_data_length(struct nffs_inode_entry *inode_entry,
uint32_t *out_len);
int nffs_inode_data_len(struct nffs_inode_entry *inode_entry,
uint32_t *out_len);
uint32_t nffs_inode_parent_id(const struct nffs_inode *inode);
int nffs_inode_delete_from_disk(struct nffs_inode *inode);
int nffs_inode_entry_from_disk(struct nffs_inode_entry *out_inode,
const struct nffs_disk_inode *disk_inode,
uint8_t area_idx, uint32_t offset);
int nffs_inode_rename(struct nffs_inode_entry *inode_entry,
struct nffs_inode_entry *new_parent,
const char *new_filename);
int nffs_inode_update(struct nffs_inode_entry *inode_entry);
void nffs_inode_insert_block(struct nffs_inode *inode,
struct nffs_block *block);
int nffs_inode_read_disk(uint8_t area_idx, uint32_t offset,
struct nffs_disk_inode *out_disk_inode);
int nffs_inode_write_disk(const struct nffs_disk_inode *disk_inode,
const char *filename, uint8_t area_idx,
uint32_t offset);
int nffs_inode_inc_refcnt(struct nffs_inode_entry *inode_entry);
int nffs_inode_dec_refcnt(struct nffs_inode_entry *inode_entry);
int nffs_inode_add_child(struct nffs_inode_entry *parent,
struct nffs_inode_entry *child);
void nffs_inode_remove_child(struct nffs_inode *child);
int nffs_inode_is_root(const struct nffs_disk_inode *disk_inode);
int nffs_inode_read_filename(struct nffs_inode_entry *inode_entry,
size_t max_len, char *out_name,
uint8_t *out_full_len);
int nffs_inode_filename_cmp_ram(const struct nffs_inode *inode,
const char *name, int name_len,
int *result);
int nffs_inode_filename_cmp_flash(const struct nffs_inode *inode1,
const struct nffs_inode *inode2,
int *result);
int nffs_inode_read(struct nffs_inode_entry *inode_entry, uint32_t offset,
uint32_t len, void *data, uint32_t *out_len);
int nffs_inode_seek(struct nffs_inode_entry *inode_entry, uint32_t offset,
uint32_t length, struct nffs_seek_info *out_seek_info);
int nffs_inode_from_entry(struct nffs_inode *out_inode,
struct nffs_inode_entry *entry);
int nffs_inode_unlink_from_ram(struct nffs_inode *inode,
struct nffs_hash_entry **out_next);
int nffs_inode_unlink_from_ram_corrupt_ok(struct nffs_inode *inode,
struct nffs_hash_entry **out_next);
int nffs_inode_unlink(struct nffs_inode *inode);
int nffs_inode_is_dummy(struct nffs_inode_entry *inode_entry);
int nffs_inode_is_deleted(struct nffs_inode_entry *inode_entry);
int nffs_inode_setflags(struct nffs_inode_entry *entry, uint8_t flag);
int nffs_inode_unsetflags(struct nffs_inode_entry *entry, uint8_t flag);
int nffs_inode_getflags(struct nffs_inode_entry *entry, uint8_t flag);
/* @misc */
int nffs_misc_gc_if_oom(void *resource, int *out_rc);
int nffs_misc_reserve_space(uint16_t space,
uint8_t *out_area_idx, uint32_t *out_area_offset);
int nffs_misc_set_num_areas(uint8_t num_areas);
int nffs_misc_validate_root_dir(void);
int nffs_misc_validate_scratch(void);
int nffs_misc_create_lost_found_dir(void);
int nffs_misc_set_max_block_data_len(uint16_t min_data_len);
int nffs_misc_reset(void);
int nffs_misc_ready(void);
int nffs_misc_desc_from_flash_area(const struct nffs_flash_desc *flash,
int *cnt, struct nffs_area_desc *nad);
/* @path */
int nffs_path_parse_next(struct nffs_path_parser *parser);
void nffs_path_parser_new(struct nffs_path_parser *parser, const char *path);
int nffs_path_find(struct nffs_path_parser *parser,
struct nffs_inode_entry **out_inode_entry,
struct nffs_inode_entry **out_parent);
int nffs_path_find_inode_entry(const char *filename,
struct nffs_inode_entry **out_inode_entry);
int nffs_path_unlink(const char *filename);
int nffs_path_rename(const char *from, const char *to);
int nffs_path_new_dir(const char *path,
struct nffs_inode_entry **out_inode_entry);
/* @restore */
int nffs_restore_full(const struct nffs_area_desc *area_descs);
/* @write */
int nffs_write_to_file(struct nffs_file *file, const void *data, int len);
#define NFFS_HASH_FOREACH(entry, i, next) \
for ((i) = 0; (i) < NFFS_HASH_SIZE; (i)++) \
for ((entry) = SLIST_FIRST(nffs_hash + (i)); \
(entry) && (((next)) = SLIST_NEXT((entry), nhe_next), 1); \
(entry) = ((next)))
#define NFFS_FLASH_LOC_NONE nffs_flash_loc(NFFS_AREA_ID_NONE, 0)
#if __ZEPHYR__
#define NFFS_LOG(lvl, ...)
#define MYNEWT_VAL(val) 0
#define ASSERT_IF_TEST(cond)
#else
/* Default to Mynewt */
#include "log/log.h"
#include "testutil/testutil.h"
#define NFFS_LOG(lvl, ...) \
LOG_ ## lvl(&nffs_log, LOG_MODULE_NFFS, __VA_ARGS__)
#endif
#ifdef __cplusplus
}
#endif
#endif