<commit_before>/*
 * 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.
 */

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include "sysinit/sysinit.h"
#include "sysflash/sysflash.h"
#include "bsp/bsp.h"
#include "hal/hal_flash.h"
#include "flash_map/flash_map.h"
#include "os/os_mempool.h"
#include "os/os_mutex.h"
#include "os/os_malloc.h"
#include "stats/stats.h"
#include "nffs_priv.h"
#include "nffs/nffs.h"
#include "fs/fs_if.h"
#include "disk/disk.h"

struct nffs_area *nffs_areas;
uint8_t nffs_num_areas;
uint8_t nffs_scratch_area_idx;
uint16_t nffs_block_max_data_sz;
struct nffs_area_desc *nffs_current_area_descs;

struct os_mempool nffs_file_pool;
struct os_mempool nffs_dir_pool;
struct os_mempool nffs_inode_entry_pool;
struct os_mempool nffs_block_entry_pool;
struct os_mempool nffs_cache_inode_pool;
struct os_mempool nffs_cache_block_pool;

void *nffs_file_mem;
void *nffs_inode_mem;
void *nffs_block_entry_mem;
void *nffs_cache_inode_mem;
void *nffs_cache_block_mem;
void *nffs_dir_mem;

struct nffs_inode_entry *nffs_root_dir;
struct nffs_inode_entry *nffs_lost_found_dir;

static struct os_mutex nffs_mutex;

struct log nffs_log;

static int nffs_open(const char *path, uint8_t access_flags,
  struct fs_file **out_file);
static int nffs_close(struct fs_file *fs_file);
static int nffs_read(struct fs_file *fs_file, uint32_t len, void *out_data,
  uint32_t *out_len);
static int nffs_write(struct fs_file *fs_file, const void *data, int len);
static int nffs_seek(struct fs_file *fs_file, uint32_t offset);
static uint32_t nffs_getpos(const struct fs_file *fs_file);
static int nffs_file_len(const struct fs_file *fs_file, uint32_t *out_len);
static int nffs_unlink(const char *path);
static int nffs_rename(const char *from, const char *to);
static int nffs_mkdir(const char *path);
static int nffs_opendir(const char *path, struct fs_dir **out_fs_dir);
static int nffs_readdir(struct fs_dir *dir, struct fs_dirent **out_dirent);
static int nffs_closedir(struct fs_dir *dir);
static int nffs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len,
  char *out_name, uint8_t *out_name_len);
static int nffs_dirent_is_dir(const struct fs_dirent *fs_dirent);

struct fs_ops nffs_ops = {
    .f_open = nffs_open,
    .f_close = nffs_close,
    .f_read = nffs_read,
    .f_write = nffs_write,

    .f_seek = nffs_seek,
    .f_getpos = nffs_getpos,
    .f_filelen = nffs_file_len,

    .f_unlink = nffs_unlink,
    .f_rename = nffs_rename,
    .f_mkdir = nffs_mkdir,

    .f_opendir = nffs_opendir,
    .f_readdir = nffs_readdir,
    .f_closedir = nffs_closedir,

    .f_dirent_name = nffs_dirent_name,
    .f_dirent_is_dir = nffs_dirent_is_dir,

    .f_name = "nffs"
};

STATS_SECT_DECL(nffs_stats) nffs_stats;
STATS_NAME_START(nffs_stats)
    STATS_NAME(nffs_stats, nffs_hashcnt_ins)
    STATS_NAME(nffs_stats, nffs_hashcnt_rm)
    STATS_NAME(nffs_stats, nffs_object_count)
    STATS_NAME(nffs_stats, nffs_iocnt_read)
    STATS_NAME(nffs_stats, nffs_iocnt_write)
    STATS_NAME(nffs_stats, nffs_gccnt)
    STATS_NAME(nffs_stats, nffs_readcnt_data)
    STATS_NAME(nffs_stats, nffs_readcnt_block)
    STATS_NAME(nffs_stats, nffs_readcnt_crc)
    STATS_NAME(nffs_stats, nffs_readcnt_copy)
    STATS_NAME(nffs_stats, nffs_readcnt_format)
    STATS_NAME(nffs_stats, nffs_readcnt_gccollate)
    STATS_NAME(nffs_stats, nffs_readcnt_inode)
    STATS_NAME(nffs_stats, nffs_readcnt_inodeent)
    STATS_NAME(nffs_stats, nffs_readcnt_rename)
    STATS_NAME(nffs_stats, nffs_readcnt_update)
    STATS_NAME(nffs_stats, nffs_readcnt_filename)
    STATS_NAME(nffs_stats, nffs_readcnt_object)
    STATS_NAME(nffs_stats, nffs_readcnt_detect)
STATS_NAME_END(nffs_stats)

static void
nffs_lock(void)
{
    int rc;

    rc = os_mutex_pend(&nffs_mutex, 0xffffffff);
    assert(rc == 0 || rc == OS_NOT_STARTED);
}

static void
nffs_unlock(void)
{
    int rc;

    rc = os_mutex_release(&nffs_mutex);
    assert(rc == 0 || rc == OS_NOT_STARTED);
}

static int
nffs_stats_init(void)
{
    int rc = 0;
    rc = stats_init_and_reg(
                    STATS_HDR(nffs_stats),
                    STATS_SIZE_INIT_PARMS(nffs_stats, STATS_SIZE_32),
                    STATS_NAME_INIT_PARMS(nffs_stats),
                    "nffs_stats");
    if (rc) {
        if (rc < 0) {
            /* multiple initializations are okay */
            rc = 0;
        } else {
            rc = FS_EOS;
        }
    }
    return rc;
}

/**
 * Opens a file at the specified path.  The result of opening a nonexistent
 * file depends on the access flags specified.  All intermediate directories
 * must already exist.
 *
 * The mode strings passed to fopen() map to nffs_open()'s access flags as
 * follows:
 *   "r"  -  FS_ACCESS_READ<commit_msg>fs/nffs: Remove not needed initalization<commit_after>/*
 * 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.
 */

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include "sysinit/sysinit.h"
#include "sysflash/sysflash.h"
#include "bsp/bsp.h"
#include "hal/hal_flash.h"
#include "flash_map/flash_map.h"
#include "os/os_mempool.h"
#include "os/os_mutex.h"
#include "os/os_malloc.h"
#include "stats/stats.h"
#include "nffs_priv.h"
#include "nffs/nffs.h"
#include "fs/fs_if.h"
#include "disk/disk.h"

struct nffs_area *nffs_areas;
uint8_t nffs_num_areas;
uint8_t nffs_scratch_area_idx;
uint16_t nffs_block_max_data_sz;
struct nffs_area_desc *nffs_current_area_descs;

struct os_mempool nffs_file_pool;
struct os_mempool nffs_dir_pool;
struct os_mempool nffs_inode_entry_pool;
struct os_mempool nffs_block_entry_pool;
struct os_mempool nffs_cache_inode_pool;
struct os_mempool nffs_cache_block_pool;

void *nffs_file_mem;
void *nffs_inode_mem;
void *nffs_block_entry_mem;
void *nffs_cache_inode_mem;
void *nffs_cache_block_mem;
void *nffs_dir_mem;

struct nffs_inode_entry *nffs_root_dir;
struct nffs_inode_entry *nffs_lost_found_dir;

static struct os_mutex nffs_mutex;

struct log nffs_log;

static int nffs_open(const char *path, uint8_t access_flags,
  struct fs_file **out_file);
static int nffs_close(struct fs_file *fs_file);
static int nffs_read(struct fs_file *fs_file, uint32_t len, void *out_data,
  uint32_t *out_len);
static int nffs_write(struct fs_file *fs_file, const void *data, int len);
static int nffs_seek(struct fs_file *fs_file, uint32_t offset);
static uint32_t nffs_getpos(const struct fs_file *fs_file);
static int nffs_file_len(const struct fs_file *fs_file, uint32_t *out_len);
static int nffs_unlink(const char *path);
static int nffs_rename(const char *from, const char *to);
static int nffs_mkdir(const char *path);
static int nffs_opendir(const char *path, struct fs_dir **out_fs_dir);
static int nffs_readdir(struct fs_dir *dir, struct fs_dirent **out_dirent);
static int nffs_closedir(struct fs_dir *dir);
static int nffs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len,
  char *out_name, uint8_t *out_name_len);
static int nffs_dirent_is_dir(const struct fs_dirent *fs_dirent);

struct fs_ops nffs_ops = {
    .f_open = nffs_open,
    .f_close = nffs_close,
    .f_read = nffs_read,
    .f_write = nffs_write,

    .f_seek = nffs_seek,
    .f_getpos = nffs_getpos,
    .f_filelen = nffs_file_len,

    .f_unlink = nffs_unlink,
    .f_rename = nffs_rename,
    .f_mkdir = nffs_mkdir,

    .f_opendir = nffs_opendir,
    .f_readdir = nffs_readdir,
    .f_closedir = nffs_closedir,

    .f_dirent_name = nffs_dirent_name,
    .f_dirent_is_dir = nffs_dirent_is_dir,

    .f_name = "nffs"
};

STATS_SECT_DECL(nffs_stats) nffs_stats;
STATS_NAME_START(nffs_stats)
    STATS_NAME(nffs_stats, nffs_hashcnt_ins)
    STATS_NAME(nffs_stats, nffs_hashcnt_rm)
    STATS_NAME(nffs_stats, nffs_object_count)
    STATS_NAME(nffs_stats, nffs_iocnt_read)
    STATS_NAME(nffs_stats, nffs_iocnt_write)
    STATS_NAME(nffs_stats, nffs_gccnt)
    STATS_NAME(nffs_stats, nffs_readcnt_data)
    STATS_NAME(nffs_stats, nffs_readcnt_block)
    STATS_NAME(nffs_stats, nffs_readcnt_crc)
    STATS_NAME(nffs_stats, nffs_readcnt_copy)
    STATS_NAME(nffs_stats, nffs_readcnt_format)
    STATS_NAME(nffs_stats, nffs_readcnt_gccollate)
    STATS_NAME(nffs_stats, nffs_readcnt_inode)
    STATS_NAME(nffs_stats, nffs_readcnt_inodeent)
    STATS_NAME(nffs_stats, nffs_readcnt_rename)
    STATS_NAME(nffs_stats, nffs_readcnt_update)
    STATS_NAME(nffs_stats, nffs_readcnt_filename)
    STATS_NAME(nffs_stats, nffs_readcnt_object)
    STATS_NAME(nffs_stats, nffs_readcnt_detect)
STATS_NAME_END(nffs_stats)

static void
nffs_lock(void)
{
    int rc;

    rc = os_mutex_pend(&nffs_mutex, 0xffffffff);
    assert(rc == 0 || rc == OS_NOT_STARTED);
}

static void
nffs_unlock(void)
{
    int rc;

    rc = os_mutex_release(&nffs_mutex);
    assert(rc == 0 || rc == OS_NOT_STARTED);
}

static int
nffs_stats_init(void)
{
    int rc;

    rc = stats_init_and_reg(
                    STATS_HDR(nffs_stats),
                    STATS_SIZE_INIT_PARMS(nffs_stats, STATS_SIZE_32),
                    STATS_NAME_INIT_PARMS(nffs_stats),
                    "nffs_stats");
    if (rc) {
        if (rc < 0) {
            /* multiple initializations are okay */
            rc = 0;
        } else {
            rc = FS_EOS;
        }
    }
    return rc;
}

/**
 * Opens a file at the specified path.  The result of opening a nonexistent
 * file depends on the access flags specified.  All intermediate directories
 * must already exist.
 *
 * The mode strings passed to fopen() map to nffs_open()'s access flags as
 * follows:
 *   "r"  -  FS_ACCESS_READ
{'fraction_non_alphanumeric': 0.0852664008698804, 'fraction_numerical': 0.004983689742660384, 'mean_word_length': 4.434268833087149, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4904414', 'n_tokens_mistral': 4426, 'n_tokens_neox': 4359, 'n_words': 974}