1*d47bcd29Schs /* $NetBSD: bfs.c,v 1.19 2019/11/10 21:16:38 chs Exp $ */
21f505522Stsutsui
31f505522Stsutsui /*-
41f505522Stsutsui * Copyright (c) 2004 The NetBSD Foundation, Inc.
51f505522Stsutsui * All rights reserved.
61f505522Stsutsui *
71f505522Stsutsui * This code is derived from software contributed to The NetBSD Foundation
81f505522Stsutsui * by UCHIYAMA Yasushi.
91f505522Stsutsui *
101f505522Stsutsui * Redistribution and use in source and binary forms, with or without
111f505522Stsutsui * modification, are permitted provided that the following conditions
121f505522Stsutsui * are met:
131f505522Stsutsui * 1. Redistributions of source code must retain the above copyright
141f505522Stsutsui * notice, this list of conditions and the following disclaimer.
151f505522Stsutsui * 2. Redistributions in binary form must reproduce the above copyright
161f505522Stsutsui * notice, this list of conditions and the following disclaimer in the
171f505522Stsutsui * documentation and/or other materials provided with the distribution.
181f505522Stsutsui *
191f505522Stsutsui * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201f505522Stsutsui * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211f505522Stsutsui * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221f505522Stsutsui * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231f505522Stsutsui * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241f505522Stsutsui * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251f505522Stsutsui * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261f505522Stsutsui * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271f505522Stsutsui * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281f505522Stsutsui * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291f505522Stsutsui * POSSIBILITY OF SUCH DAMAGE.
301f505522Stsutsui */
311f505522Stsutsui
321f505522Stsutsui #include <sys/cdefs.h>
331f505522Stsutsui
34*d47bcd29Schs __KERNEL_RCSID(0, "$NetBSD: bfs.c,v 1.19 2019/11/10 21:16:38 chs Exp $");
351f505522Stsutsui #define BFS_DEBUG
361f505522Stsutsui
371f505522Stsutsui #include <sys/param.h>
381f505522Stsutsui #include <sys/kernel.h>
391f505522Stsutsui #include <sys/types.h>
401f505522Stsutsui #include <sys/systm.h>
411f505522Stsutsui #include <sys/errno.h>
421f505522Stsutsui #include <sys/malloc.h>
431f505522Stsutsui #include <sys/time.h>
441f505522Stsutsui
451f505522Stsutsui #ifdef _KERNEL
46835b0326Spooka MALLOC_JUSTDEFINE(M_BFS, "sysvbfs core", "sysvbfs internal structures");
471f505522Stsutsui #define __MALLOC(s, t, f) malloc(s, t, f)
481f505522Stsutsui #define __FREE(a, s, t) free(a, t)
491f505522Stsutsui #elif defined _STANDALONE
501f505522Stsutsui #include <lib/libsa/stand.h>
511f505522Stsutsui #include <lib/libkern/libkern.h>
521f505522Stsutsui #define __MALLOC(s, t, f) alloc(s)
537a10e95eStsutsui #define __FREE(a, s, t) dealloc(a, s)
541f505522Stsutsui #else
551f505522Stsutsui #include "local.h"
561f505522Stsutsui #define __MALLOC(s, t, f) malloc(s)
571f505522Stsutsui #define __FREE(a, s, t) free(a)
581f505522Stsutsui #endif
591f505522Stsutsui #include <fs/sysvbfs/bfs.h>
601f505522Stsutsui
611f505522Stsutsui #ifdef BFS_DEBUG
621f505522Stsutsui #define DPRINTF(on, fmt, args...) if (on) printf(fmt, ##args)
631f505522Stsutsui #else
641f505522Stsutsui #define DPRINTF(arg...) ((void)0)
651f505522Stsutsui #endif
661f505522Stsutsui
671f505522Stsutsui #define ROUND_SECTOR(x) (((x) + 511) & ~511)
681f505522Stsutsui #define TRUNC_SECTOR(x) ((x) & ~511)
691f505522Stsutsui
701f505522Stsutsui #define STATIC
711f505522Stsutsui
721f505522Stsutsui STATIC int bfs_init_superblock(struct bfs *, int, size_t *);
731f505522Stsutsui STATIC int bfs_init_inode(struct bfs *, uint8_t *, size_t *);
741f505522Stsutsui STATIC int bfs_init_dirent(struct bfs *, uint8_t *);
751f505522Stsutsui
761f505522Stsutsui /* super block ops. */
77712239e3Sthorpej STATIC bool bfs_superblock_valid(const struct bfs_super_block *);
78712239e3Sthorpej STATIC bool bfs_writeback_dirent(const struct bfs *, struct bfs_dirent *,
79712239e3Sthorpej bool);
80712239e3Sthorpej STATIC bool bfs_writeback_inode(const struct bfs *, struct bfs_inode *);
811f505522Stsutsui
821f505522Stsutsui int
bfs_init2(struct bfs ** bfsp,int bfs_sector,struct sector_io_ops * io,bool debug)831f505522Stsutsui bfs_init2(struct bfs **bfsp, int bfs_sector, struct sector_io_ops *io,
84712239e3Sthorpej bool debug)
851f505522Stsutsui {
861f505522Stsutsui struct bfs *bfs;
871f505522Stsutsui size_t memsize;
881f505522Stsutsui uint8_t *p;
891f505522Stsutsui int err;
901f505522Stsutsui
911f505522Stsutsui /* 1. */
921f505522Stsutsui DPRINTF(debug, "bfs sector = %d\n", bfs_sector);
93*d47bcd29Schs if ((bfs = (void *)__MALLOC(sizeof(struct bfs), M_BFS, M_WAITOK)) == 0)
941f505522Stsutsui return ENOMEM;
951f505522Stsutsui memset(bfs, 0, sizeof *bfs);
961f505522Stsutsui bfs->io = io;
971f505522Stsutsui bfs->debug = debug;
981f505522Stsutsui
991f505522Stsutsui /* 2. */
1001f505522Stsutsui if ((err = bfs_init_superblock(bfs, bfs_sector, &memsize)) != 0) {
1011f505522Stsutsui bfs_fini(bfs);
1021f505522Stsutsui return err;
1031f505522Stsutsui }
1046bfe6be4Smartin DPRINTF(debug, "bfs super block + inode area = %zd\n", memsize);
1051f505522Stsutsui bfs->super_block_size = memsize;
106*d47bcd29Schs if ((p = (void *)__MALLOC(memsize, M_BFS, M_WAITOK)) == 0) {
1071f505522Stsutsui bfs_fini(bfs);
1081f505522Stsutsui return ENOMEM;
1091f505522Stsutsui }
1101f505522Stsutsui /* 3. */
1111f505522Stsutsui if ((err = bfs_init_inode(bfs, p, &memsize)) != 0) {
1121f505522Stsutsui bfs_fini(bfs);
1131f505522Stsutsui return err;
1141f505522Stsutsui }
1156bfe6be4Smartin DPRINTF(debug, "bfs dirent area = %zd\n", memsize);
1161f505522Stsutsui bfs->dirent_size = memsize;
117*d47bcd29Schs if ((p = (void *)__MALLOC(memsize, M_BFS, M_WAITOK)) == 0) {
1181f505522Stsutsui bfs_fini(bfs);
1191f505522Stsutsui return ENOMEM;
1201f505522Stsutsui }
1211f505522Stsutsui /* 4. */
1221f505522Stsutsui if ((err = bfs_init_dirent(bfs, p)) != 0) {
1231f505522Stsutsui bfs_fini(bfs);
1241f505522Stsutsui return err;
1251f505522Stsutsui }
1261f505522Stsutsui
1271f505522Stsutsui #ifdef BFS_DEBUG
1281f505522Stsutsui bfs_dump(bfs);
1291f505522Stsutsui #endif
1301f505522Stsutsui *bfsp = bfs;
1311f505522Stsutsui
1321f505522Stsutsui return 0;
1331f505522Stsutsui }
1341f505522Stsutsui
1351f505522Stsutsui void
bfs_fini(struct bfs * bfs)1361f505522Stsutsui bfs_fini(struct bfs *bfs)
1371f505522Stsutsui {
1381f505522Stsutsui
1391f505522Stsutsui if (bfs == 0)
1401f505522Stsutsui return;
1411f505522Stsutsui if (bfs->super_block)
1421f505522Stsutsui __FREE(bfs->super_block, bfs->super_block_size, M_BFS);
1431f505522Stsutsui if (bfs->dirent)
1441f505522Stsutsui __FREE(bfs->dirent, bfs->dirent_size, M_BFS);
1451f505522Stsutsui __FREE(bfs, sizeof(struct bfs), M_BFS);
1461f505522Stsutsui }
1471f505522Stsutsui
1481f505522Stsutsui STATIC int
bfs_init_superblock(struct bfs * bfs,int bfs_sector,size_t * required_memory)1491f505522Stsutsui bfs_init_superblock(struct bfs *bfs, int bfs_sector, size_t *required_memory)
1501f505522Stsutsui {
1511f505522Stsutsui struct bfs_super_block super;
1521f505522Stsutsui
1531f505522Stsutsui bfs->start_sector = bfs_sector;
1541f505522Stsutsui
1551f505522Stsutsui /* Read super block */
1561f505522Stsutsui if (!bfs->io->read(bfs->io, (uint8_t *)&super, bfs_sector))
1571f505522Stsutsui return EIO;
1581f505522Stsutsui
1591f505522Stsutsui if (!bfs_superblock_valid(&super))
1601f505522Stsutsui return EINVAL;
1611f505522Stsutsui
1621f505522Stsutsui /* i-node table size */
1631f505522Stsutsui bfs->data_start = super.header.data_start_byte;
1641f505522Stsutsui bfs->data_end = super.header.data_end_byte;
1651f505522Stsutsui
1661f505522Stsutsui bfs->max_inode = (bfs->data_start - sizeof(struct bfs_super_block)) /
1671f505522Stsutsui sizeof(struct bfs_inode);
1681f505522Stsutsui
1691f505522Stsutsui *required_memory = ROUND_SECTOR(bfs->data_start);
1701f505522Stsutsui
1711f505522Stsutsui return 0;
1721f505522Stsutsui }
1731f505522Stsutsui
1741f505522Stsutsui STATIC int
bfs_init_inode(struct bfs * bfs,uint8_t * p,size_t * required_memory)1751f505522Stsutsui bfs_init_inode(struct bfs *bfs, uint8_t *p, size_t *required_memory)
1761f505522Stsutsui {
1771f505522Stsutsui struct bfs_inode *inode, *root_inode;
1781f505522Stsutsui int i;
1791f505522Stsutsui
1801f505522Stsutsui if (!bfs->io->read_n(bfs->io, p, bfs->start_sector,
1811f505522Stsutsui bfs->data_start >> DEV_BSHIFT))
1821f505522Stsutsui return EIO;
1831f505522Stsutsui
1841f505522Stsutsui bfs->super_block = (struct bfs_super_block *)p;
1851f505522Stsutsui bfs->inode = (struct bfs_inode *)(p + sizeof(struct bfs_super_block));
1861f505522Stsutsui p += bfs->data_start;
1871f505522Stsutsui
1881f505522Stsutsui bfs->n_inode = 0;
1891f505522Stsutsui inode = bfs->inode;
1901f505522Stsutsui root_inode = 0;
1911f505522Stsutsui for (i = 0; i < bfs->max_inode; i++, inode++) {
1921f505522Stsutsui if (inode->number != 0) {
1931f505522Stsutsui bfs->n_inode++;
1941f505522Stsutsui if (inode->number == BFS_ROOT_INODE)
1951f505522Stsutsui root_inode = inode;
1961f505522Stsutsui }
1971f505522Stsutsui }
1981f505522Stsutsui DPRINTF(bfs->debug, "inode: %d/%d\n", bfs->n_inode, bfs->max_inode);
1991f505522Stsutsui
2001f505522Stsutsui if (root_inode == 0) {
2011f505522Stsutsui DPRINTF(bfs->debug, "no root directory.\n");
2021f505522Stsutsui return ENOTDIR;
2031f505522Stsutsui }
2041f505522Stsutsui /* dirent table size */
2051f505522Stsutsui DPRINTF(bfs->debug, "root inode: %d-%d\n", root_inode->start_sector,
2061f505522Stsutsui root_inode->end_sector);
2071f505522Stsutsui bfs->root_inode = root_inode;
2081f505522Stsutsui
2091f505522Stsutsui *required_memory = (root_inode->end_sector -
2101f505522Stsutsui root_inode->start_sector + 1) << DEV_BSHIFT;
2111f505522Stsutsui
2121f505522Stsutsui return 0;
2131f505522Stsutsui }
2141f505522Stsutsui
2151f505522Stsutsui STATIC int
bfs_init_dirent(struct bfs * bfs,uint8_t * p)2161f505522Stsutsui bfs_init_dirent(struct bfs *bfs, uint8_t *p)
2171f505522Stsutsui {
2181f505522Stsutsui struct bfs_dirent *file;
2191f505522Stsutsui struct bfs_inode *inode = bfs->root_inode;
2201f505522Stsutsui int i, n;
2211f505522Stsutsui
2221f505522Stsutsui n = inode->end_sector - inode->start_sector + 1;
2231f505522Stsutsui
2241f505522Stsutsui if (!bfs->io->read_n(bfs->io, p,
2251f505522Stsutsui bfs->start_sector + inode->start_sector, n))
2261f505522Stsutsui return EIO;
2271f505522Stsutsui
2281f505522Stsutsui bfs->dirent = (struct bfs_dirent *)p;
2291f505522Stsutsui bfs->max_dirent = (n << DEV_BSHIFT) / sizeof(struct bfs_dirent);
2301f505522Stsutsui
2311f505522Stsutsui file = bfs->dirent;
2321f505522Stsutsui bfs->n_dirent = 0;
2331f505522Stsutsui for (i = 0; i < bfs->max_dirent; i++, file++)
2341f505522Stsutsui if (file->inode != 0)
2351f505522Stsutsui bfs->n_dirent++;
2361f505522Stsutsui
2371f505522Stsutsui DPRINTF(bfs->debug, "dirent: %d/%d\n", bfs->n_dirent, bfs->max_dirent);
2381f505522Stsutsui
2391f505522Stsutsui return 0;
2401f505522Stsutsui }
2411f505522Stsutsui
2421f505522Stsutsui int
bfs_file_read(const struct bfs * bfs,const char * fname,void * buf,size_t bufsz,size_t * read_size)2431f505522Stsutsui bfs_file_read(const struct bfs *bfs, const char *fname, void *buf, size_t bufsz,
2441f505522Stsutsui size_t *read_size)
2451f505522Stsutsui {
2461f505522Stsutsui int start, end, n;
2471f505522Stsutsui size_t sz;
2481f505522Stsutsui uint8_t tmpbuf[DEV_BSIZE];
2491f505522Stsutsui uint8_t *p;
2501f505522Stsutsui
2511f505522Stsutsui if (!bfs_file_lookup(bfs, fname, &start, &end, &sz))
2521f505522Stsutsui return ENOENT;
2531f505522Stsutsui
2541f505522Stsutsui if (sz > bufsz)
2551f505522Stsutsui return ENOMEM;
2561f505522Stsutsui
2571f505522Stsutsui p = buf;
2581f505522Stsutsui n = end - start;
259c519d37fSuch if (!bfs->io->read_n(bfs->io, p, start, n))
260c519d37fSuch return EIO;
2611f505522Stsutsui /* last sector */
2621f505522Stsutsui n *= DEV_BSIZE;
263c519d37fSuch if (!bfs->io->read(bfs->io, tmpbuf, end))
264c519d37fSuch return EIO;
2651f505522Stsutsui memcpy(p + n, tmpbuf, sz - n);
2661f505522Stsutsui
2671f505522Stsutsui if (read_size)
2681f505522Stsutsui *read_size = sz;
2691f505522Stsutsui
2701f505522Stsutsui return 0;
2711f505522Stsutsui }
2721f505522Stsutsui
2731f505522Stsutsui int
bfs_file_write(struct bfs * bfs,const char * fname,void * buf,size_t bufsz)2741f505522Stsutsui bfs_file_write(struct bfs *bfs, const char *fname, void *buf,
2751f505522Stsutsui size_t bufsz)
2761f505522Stsutsui {
2771f505522Stsutsui struct bfs_fileattr attr;
2781f505522Stsutsui struct bfs_dirent *dirent;
279b5825ccfStsutsui char name[BFS_FILENAME_MAXLEN];
2801f505522Stsutsui int err;
2811f505522Stsutsui
2821f505522Stsutsui strncpy(name, fname, BFS_FILENAME_MAXLEN);
2831f505522Stsutsui
2841f505522Stsutsui if (bfs_dirent_lookup_by_name(bfs, name, &dirent)) {
2851f505522Stsutsui struct bfs_inode *inode;
2861f505522Stsutsui if (!bfs_inode_lookup(bfs, dirent->inode, &inode)) {
2871f505522Stsutsui DPRINTF(bfs->debug, "%s: dirent found, but inode "
2881f505522Stsutsui "not found. inconsistent filesystem.\n",
2899b2b412cSperry __func__);
2901f505522Stsutsui return ENOENT;
2911f505522Stsutsui }
2921f505522Stsutsui attr = inode->attr; /* copy old attribute */
2939cd2f4b9Shannken bfs_file_delete(bfs, name, false);
2941f505522Stsutsui if ((err = bfs_file_create(bfs, name, buf, bufsz, &attr)) != 0)
2951f505522Stsutsui return err;
2961f505522Stsutsui } else {
2971f505522Stsutsui memset(&attr, 0xff, sizeof attr); /* Set VNOVAL all */
2981f505522Stsutsui #ifdef _KERNEL
29993198524Smartin attr.atime = time_second;
30093198524Smartin attr.ctime = time_second;
30193198524Smartin attr.mtime = time_second;
3021f505522Stsutsui #endif
3031f505522Stsutsui if ((err = bfs_file_create(bfs, name, buf, bufsz, &attr)) != 0)
3041f505522Stsutsui return err;
3051f505522Stsutsui }
3061f505522Stsutsui
3071f505522Stsutsui return 0;
3081f505522Stsutsui }
3091f505522Stsutsui
3101f505522Stsutsui int
bfs_file_delete(struct bfs * bfs,const char * fname,bool keep_inode)3119cd2f4b9Shannken bfs_file_delete(struct bfs *bfs, const char *fname, bool keep_inode)
3121f505522Stsutsui {
3131f505522Stsutsui struct bfs_inode *inode;
3141f505522Stsutsui struct bfs_dirent *dirent;
3151f505522Stsutsui
3161f505522Stsutsui if (!bfs_dirent_lookup_by_name(bfs, fname, &dirent))
3171f505522Stsutsui return ENOENT;
3181f505522Stsutsui
3199cd2f4b9Shannken if (!keep_inode && !bfs_inode_lookup(bfs, dirent->inode, &inode))
3201f505522Stsutsui return ENOENT;
3211f505522Stsutsui
3221f505522Stsutsui memset(dirent, 0, sizeof *dirent);
3239cd2f4b9Shannken bfs->n_dirent--;
3249cd2f4b9Shannken bfs_writeback_dirent(bfs, dirent, false);
3259cd2f4b9Shannken
3269cd2f4b9Shannken if (!keep_inode) {
3271f505522Stsutsui memset(inode, 0, sizeof *inode);
3281f505522Stsutsui bfs->n_inode--;
3291f505522Stsutsui bfs_writeback_inode(bfs, inode);
3309cd2f4b9Shannken }
3319b2b412cSperry DPRINTF(bfs->debug, "%s: \"%s\" deleted.\n", __func__, fname);
3321f505522Stsutsui
3331f505522Stsutsui return 0;
3341f505522Stsutsui }
3351f505522Stsutsui
3361f505522Stsutsui int
bfs_file_rename(struct bfs * bfs,const char * from_name,const char * to_name)3371f505522Stsutsui bfs_file_rename(struct bfs *bfs, const char *from_name, const char *to_name)
3381f505522Stsutsui {
3391f505522Stsutsui struct bfs_dirent *dirent;
3401f505522Stsutsui int err = 0;
3411f505522Stsutsui
3421f505522Stsutsui if (!bfs_dirent_lookup_by_name(bfs, from_name, &dirent)) {
3431f505522Stsutsui err = ENOENT;
3441f505522Stsutsui goto out;
3451f505522Stsutsui }
3461f505522Stsutsui
3471f505522Stsutsui strncpy(dirent->name, to_name, BFS_FILENAME_MAXLEN);
3484f3d5a9cSthorpej bfs_writeback_dirent(bfs, dirent, false);
3491f505522Stsutsui
3501f505522Stsutsui out:
3519b2b412cSperry DPRINTF(bfs->debug, "%s: \"%s\" -> \"%s\" error=%d.\n", __func__,
3521f505522Stsutsui from_name, to_name, err);
3531f505522Stsutsui
3541f505522Stsutsui return err;
3551f505522Stsutsui }
3561f505522Stsutsui
3571f505522Stsutsui int
bfs_file_create(struct bfs * bfs,const char * fname,void * buf,size_t bufsz,const struct bfs_fileattr * attr)3581f505522Stsutsui bfs_file_create(struct bfs *bfs, const char *fname, void *buf, size_t bufsz,
3591f505522Stsutsui const struct bfs_fileattr *attr)
3601f505522Stsutsui {
3611f505522Stsutsui struct bfs_inode *inode;
3621f505522Stsutsui struct bfs_dirent *file;
3631f505522Stsutsui int i, j, n, start;
3641f505522Stsutsui uint8_t *p, tmpbuf[DEV_BSIZE];
3651f505522Stsutsui int err;
3661f505522Stsutsui
3671f505522Stsutsui /* Find free i-node and data block */
3681f505522Stsutsui if ((err = bfs_inode_alloc(bfs, &inode, &j, &start)) != 0)
3691f505522Stsutsui return err;
3701f505522Stsutsui
3711f505522Stsutsui /* File size (unit block) */
3721f505522Stsutsui n = (ROUND_SECTOR(bufsz) >> DEV_BSHIFT) - 1;
3731f505522Stsutsui if (n < 0) /* bufsz == 0 */
3741f505522Stsutsui n = 0;
3751f505522Stsutsui
3761f505522Stsutsui if ((start + n) * DEV_BSIZE >= bfs->data_end) {
3771f505522Stsutsui DPRINTF(bfs->debug, "disk full.\n");
3781f505522Stsutsui return ENOSPC;
3791f505522Stsutsui }
3801f505522Stsutsui
3811f505522Stsutsui /* Find free dirent */
3821f505522Stsutsui for (file = bfs->dirent, i = 0; i < bfs->max_dirent; i++, file++)
3831f505522Stsutsui if (file->inode == 0)
3841f505522Stsutsui break;
3851f505522Stsutsui if (i == bfs->max_dirent) {
3861f505522Stsutsui DPRINTF(bfs->debug, "dirent full.\n");
3871f505522Stsutsui return ENOSPC;
3881f505522Stsutsui }
3891f505522Stsutsui
3901f505522Stsutsui /* i-node */
3911f505522Stsutsui memset(inode, 0, sizeof *inode);
3921f505522Stsutsui inode->number = j;
3931f505522Stsutsui inode->start_sector = start;
3941f505522Stsutsui inode->end_sector = start + n;
3951f505522Stsutsui inode->eof_offset_byte = start * DEV_BSIZE + bufsz - 1;
3961f505522Stsutsui /* i-node attribute */
3971f505522Stsutsui inode->attr.type = 1;
3981f505522Stsutsui inode->attr.mode = 0;
3991f505522Stsutsui inode->attr.nlink = 1;
4001f505522Stsutsui bfs_inode_set_attr(bfs, inode, attr);
4011f505522Stsutsui
4021f505522Stsutsui /* Dirent */
4031f505522Stsutsui memset(file, 0, sizeof *file);
4041f505522Stsutsui file->inode = inode->number;
4051f505522Stsutsui strncpy(file->name, fname, BFS_FILENAME_MAXLEN);
4061f505522Stsutsui
4079b2b412cSperry DPRINTF(bfs->debug, "%s: start %d end %d\n", __func__,
4081f505522Stsutsui inode->start_sector, inode->end_sector);
4091f505522Stsutsui
4101f505522Stsutsui if (buf != 0) {
4111f505522Stsutsui p = (uint8_t *)buf;
4121f505522Stsutsui /* Data block */
4131f505522Stsutsui n = 0;
4141f505522Stsutsui for (i = inode->start_sector; i < inode->end_sector; i++) {
4151f505522Stsutsui if (!bfs->io->write(bfs->io, p, bfs->start_sector + i))
4161f505522Stsutsui return EIO;
4171f505522Stsutsui p += DEV_BSIZE;
4181f505522Stsutsui n += DEV_BSIZE;
4191f505522Stsutsui }
4201f505522Stsutsui /* last sector */
4211f505522Stsutsui memset(tmpbuf, 0, DEV_BSIZE);
4221f505522Stsutsui memcpy(tmpbuf, p, bufsz - n);
4231f505522Stsutsui if (!bfs->io->write(bfs->io, tmpbuf, bfs->start_sector + i))
4241f505522Stsutsui return EIO;
4251f505522Stsutsui }
4261f505522Stsutsui /* Update */
4271f505522Stsutsui bfs->n_inode++;
4281f505522Stsutsui bfs->n_dirent++;
4294f3d5a9cSthorpej bfs_writeback_dirent(bfs, file, true);
4301f505522Stsutsui bfs_writeback_inode(bfs, inode);
4311f505522Stsutsui
4321f505522Stsutsui return 0;
4331f505522Stsutsui }
4341f505522Stsutsui
435712239e3Sthorpej STATIC bool
bfs_writeback_dirent(const struct bfs * bfs,struct bfs_dirent * dir,bool create)4361f505522Stsutsui bfs_writeback_dirent(const struct bfs *bfs, struct bfs_dirent *dir,
437712239e3Sthorpej bool create)
4381f505522Stsutsui {
4391f505522Stsutsui struct bfs_dirent *dir_base = bfs->dirent;
4401f505522Stsutsui struct bfs_inode *root_inode = bfs->root_inode;
4416bfe6be4Smartin uintptr_t eof;
4421f505522Stsutsui int i;
4431f505522Stsutsui
4441f505522Stsutsui i = ((dir - dir_base) * sizeof *dir) >> DEV_BSHIFT;
4451f505522Stsutsui
4466bfe6be4Smartin eof = (uintptr_t)(dir + 1) - 1;
4476bfe6be4Smartin eof = eof - (uintptr_t)dir_base +
4481f505522Stsutsui (root_inode->start_sector << DEV_BSHIFT);
4491f505522Stsutsui
4501f505522Stsutsui /* update root directory inode */
4511f505522Stsutsui #if 0
4521f505522Stsutsui printf("eof new=%d old=%d\n", eof, root_inode->eof_offset_byte);
4531f505522Stsutsui #endif
4541f505522Stsutsui if (create) {
4551f505522Stsutsui if (eof > root_inode->eof_offset_byte) {
4561f505522Stsutsui root_inode->eof_offset_byte = eof;
4571f505522Stsutsui }
4581f505522Stsutsui } else {
4591f505522Stsutsui /* delete the last entry */
4601f505522Stsutsui if (eof == root_inode->eof_offset_byte) {
4611f505522Stsutsui root_inode->eof_offset_byte = eof - sizeof *dir;
4621f505522Stsutsui }
4631f505522Stsutsui }
4641f505522Stsutsui bfs_writeback_inode(bfs, root_inode);
4651f505522Stsutsui
4661f505522Stsutsui /* update dirent */
4671f505522Stsutsui return bfs->io->write(bfs->io, (uint8_t *)dir_base + (i << DEV_BSHIFT),
4681f505522Stsutsui bfs->start_sector + bfs->root_inode->start_sector + i);
4691f505522Stsutsui }
4701f505522Stsutsui
471712239e3Sthorpej STATIC bool
bfs_writeback_inode(const struct bfs * bfs,struct bfs_inode * inode)4721f505522Stsutsui bfs_writeback_inode(const struct bfs *bfs, struct bfs_inode *inode)
4731f505522Stsutsui {
4741f505522Stsutsui struct bfs_inode *inode_base = bfs->inode;
4751f505522Stsutsui int i;
4761f505522Stsutsui
4771f505522Stsutsui i = ((inode - inode_base) * sizeof *inode) >> DEV_BSHIFT;
4781f505522Stsutsui
4791f505522Stsutsui return bfs->io->write(bfs->io,
4801f505522Stsutsui (uint8_t *)inode_base + (i << DEV_BSHIFT),
4811f505522Stsutsui bfs->start_sector + 1/*super block*/ + i);
4821f505522Stsutsui }
4831f505522Stsutsui
484712239e3Sthorpej bool
bfs_file_lookup(const struct bfs * bfs,const char * fname,int * start,int * end,size_t * size)4851f505522Stsutsui bfs_file_lookup(const struct bfs *bfs, const char *fname, int *start, int *end,
4861f505522Stsutsui size_t *size)
4871f505522Stsutsui {
4881f505522Stsutsui struct bfs_inode *inode;
4891f505522Stsutsui struct bfs_dirent *dirent;
4901f505522Stsutsui
4911f505522Stsutsui if (!bfs_dirent_lookup_by_name(bfs, fname, &dirent))
4924f3d5a9cSthorpej return false;
4931f505522Stsutsui if (!bfs_inode_lookup(bfs, dirent->inode, &inode))
4944f3d5a9cSthorpej return false;
4951f505522Stsutsui
4961f505522Stsutsui if (start)
4971f505522Stsutsui *start = inode->start_sector + bfs->start_sector;
4981f505522Stsutsui if (end)
4991f505522Stsutsui *end = inode->end_sector + bfs->start_sector;
5001f505522Stsutsui if (size)
5011f505522Stsutsui *size = bfs_file_size(inode);
5021f505522Stsutsui
5036bfe6be4Smartin DPRINTF(bfs->debug, "%s: %d + %d -> %d (%zd)\n",
5041f505522Stsutsui fname, bfs->start_sector, inode->start_sector,
5051f505522Stsutsui inode->end_sector, *size);
5061f505522Stsutsui
5074f3d5a9cSthorpej return true;
5081f505522Stsutsui }
5091f505522Stsutsui
510712239e3Sthorpej bool
bfs_dirent_lookup_by_inode(const struct bfs * bfs,int inode,struct bfs_dirent ** dirent)5111f505522Stsutsui bfs_dirent_lookup_by_inode(const struct bfs *bfs, int inode,
5121f505522Stsutsui struct bfs_dirent **dirent)
5131f505522Stsutsui {
5141f505522Stsutsui struct bfs_dirent *file;
5151f505522Stsutsui int i;
5161f505522Stsutsui
5171f505522Stsutsui for (file = bfs->dirent, i = 0; i < bfs->max_dirent; i++, file++)
5181f505522Stsutsui if (file->inode == inode)
5191f505522Stsutsui break;
5201f505522Stsutsui
5211f505522Stsutsui if (i == bfs->max_dirent)
5224f3d5a9cSthorpej return false;
5231f505522Stsutsui
5241f505522Stsutsui *dirent = file;
5251f505522Stsutsui
5264f3d5a9cSthorpej return true;
5271f505522Stsutsui }
5281f505522Stsutsui
529712239e3Sthorpej bool
bfs_dirent_lookup_by_name(const struct bfs * bfs,const char * fname,struct bfs_dirent ** dirent)5301f505522Stsutsui bfs_dirent_lookup_by_name(const struct bfs *bfs, const char *fname,
5311f505522Stsutsui struct bfs_dirent **dirent)
5321f505522Stsutsui {
5331f505522Stsutsui struct bfs_dirent *file;
5341f505522Stsutsui int i;
5351f505522Stsutsui
5361f505522Stsutsui for (file = bfs->dirent, i = 0; i < bfs->max_dirent; i++, file++)
5371f505522Stsutsui if ((file->inode != 0) &&
5381f505522Stsutsui (strncmp(file->name, fname, BFS_FILENAME_MAXLEN) ==0))
5391f505522Stsutsui break;
5401f505522Stsutsui
5411f505522Stsutsui if (i == bfs->max_dirent)
5424f3d5a9cSthorpej return false;
5431f505522Stsutsui
5441f505522Stsutsui *dirent = file;
5451f505522Stsutsui
5464f3d5a9cSthorpej return true;
5471f505522Stsutsui }
5481f505522Stsutsui
549712239e3Sthorpej bool
bfs_inode_lookup(const struct bfs * bfs,ino_t n,struct bfs_inode ** iinode)5501f505522Stsutsui bfs_inode_lookup(const struct bfs *bfs, ino_t n, struct bfs_inode **iinode)
5511f505522Stsutsui {
5521f505522Stsutsui struct bfs_inode *inode;
5531f505522Stsutsui int i;
5541f505522Stsutsui
5551f505522Stsutsui for (inode = bfs->inode, i = 0; i < bfs->max_inode; i++, inode++)
5561f505522Stsutsui if (inode->number == n)
5571f505522Stsutsui break;
5581f505522Stsutsui
5591f505522Stsutsui if (i == bfs->max_inode)
5604f3d5a9cSthorpej return false;
5611f505522Stsutsui
5621f505522Stsutsui *iinode = inode;
5631f505522Stsutsui
5644f3d5a9cSthorpej return true;
5651f505522Stsutsui }
5661f505522Stsutsui
5679cd2f4b9Shannken int
bfs_inode_delete(struct bfs * bfs,ino_t ino)5689cd2f4b9Shannken bfs_inode_delete(struct bfs *bfs, ino_t ino)
5699cd2f4b9Shannken {
5709cd2f4b9Shannken struct bfs_inode *inode;
5719cd2f4b9Shannken
5729cd2f4b9Shannken if (!bfs_inode_lookup(bfs, ino, &inode))
5739cd2f4b9Shannken return ENOENT;
5749cd2f4b9Shannken
5759cd2f4b9Shannken memset(inode, 0, sizeof *inode);
5769cd2f4b9Shannken bfs->n_inode--;
5779cd2f4b9Shannken
5789cd2f4b9Shannken bfs_writeback_inode(bfs, inode);
5799cd2f4b9Shannken DPRINTF(bfs->debug, "%s: %lld deleted.\n", __func__, (long long)ino);
5809cd2f4b9Shannken
5819cd2f4b9Shannken return 0;
5829cd2f4b9Shannken }
5839cd2f4b9Shannken
5849cd2f4b9Shannken
5851f505522Stsutsui size_t
bfs_file_size(const struct bfs_inode * inode)5861f505522Stsutsui bfs_file_size(const struct bfs_inode *inode)
5871f505522Stsutsui {
5881f505522Stsutsui
5891f505522Stsutsui return inode->eof_offset_byte - inode->start_sector * DEV_BSIZE + 1;
5901f505522Stsutsui }
5911f505522Stsutsui
5921f505522Stsutsui STATIC int
bfs_inode_alloc(const struct bfs * bfs,struct bfs_inode ** free_inode,int * free_inode_number,int * free_block)5931f505522Stsutsui bfs_inode_alloc(const struct bfs *bfs, struct bfs_inode **free_inode,
5941f505522Stsutsui int *free_inode_number, int *free_block)
5951f505522Stsutsui {
5961f505522Stsutsui struct bfs_inode *jnode, *inode;
5971f505522Stsutsui int i, j, start;
5981f505522Stsutsui
5991f505522Stsutsui j = start = 0;
6001f505522Stsutsui inode = bfs->inode;
6011f505522Stsutsui jnode = 0;
6021f505522Stsutsui
6031f505522Stsutsui for (i = BFS_ROOT_INODE; i < bfs->max_inode; i++, inode++) {
6041f505522Stsutsui /* Steal i-node # */
6051f505522Stsutsui if (j == 0)
6061f505522Stsutsui j = i;
6071f505522Stsutsui
6081f505522Stsutsui /* Get free i-node */
6091f505522Stsutsui if (jnode == 0 && (inode->number == 0))
6101f505522Stsutsui jnode = inode;
6111f505522Stsutsui
6121f505522Stsutsui /* Get free i-node # and data block */
6131f505522Stsutsui if (inode->number != 0) {
6141f505522Stsutsui if (inode->end_sector > start)
6151f505522Stsutsui start = inode->end_sector;
6161f505522Stsutsui if (inode->number == j)
6171f505522Stsutsui j = 0; /* conflict */
6181f505522Stsutsui }
6191f505522Stsutsui }
6201f505522Stsutsui start++;
6211f505522Stsutsui
6221f505522Stsutsui if (jnode == 0) {
6231f505522Stsutsui DPRINTF(bfs->debug, "i-node full.\n");
6241f505522Stsutsui return ENOSPC;
6251f505522Stsutsui }
6261f505522Stsutsui
6271f505522Stsutsui if (start * DEV_BSIZE >= bfs->data_end) {
6281f505522Stsutsui DPRINTF(bfs->debug, "data block full.\n");
6291f505522Stsutsui /* compaction here ? */
6301f505522Stsutsui return ENOSPC;
6311f505522Stsutsui }
6321f505522Stsutsui if (free_inode)
6331f505522Stsutsui *free_inode = jnode;
6341f505522Stsutsui if (free_inode_number)
6351f505522Stsutsui *free_inode_number = j;
6361f505522Stsutsui if (free_block)
6371f505522Stsutsui *free_block = start;
6381f505522Stsutsui
6391f505522Stsutsui return 0;
6401f505522Stsutsui }
6411f505522Stsutsui
6421f505522Stsutsui void
bfs_inode_set_attr(const struct bfs * bfs,struct bfs_inode * inode,const struct bfs_fileattr * from)6431f505522Stsutsui bfs_inode_set_attr(const struct bfs *bfs, struct bfs_inode *inode,
6441f505522Stsutsui const struct bfs_fileattr *from)
6451f505522Stsutsui {
6461f505522Stsutsui struct bfs_fileattr *to = &inode->attr;
6471f505522Stsutsui
6481f505522Stsutsui if (from != NULL) {
6491f505522Stsutsui if (from->uid != (uid_t)-1)
6501f505522Stsutsui to->uid = from->uid;
6516b981736Sagc if (from->gid != (gid_t)-1)
6521f505522Stsutsui to->gid = from->gid;
6531f505522Stsutsui if (from->mode != (mode_t)-1)
6541f505522Stsutsui to->mode = from->mode;
6551f505522Stsutsui if (from->atime != -1)
6561f505522Stsutsui to->atime = from->atime;
6571f505522Stsutsui if (from->ctime != -1)
6581f505522Stsutsui to->ctime = from->ctime;
6591f505522Stsutsui if (from->mtime != -1)
6601f505522Stsutsui to->mtime = from->mtime;
6611f505522Stsutsui }
6621f505522Stsutsui bfs_writeback_inode(bfs, inode);
6631f505522Stsutsui }
6641f505522Stsutsui
665712239e3Sthorpej STATIC bool
bfs_superblock_valid(const struct bfs_super_block * super)6661f505522Stsutsui bfs_superblock_valid(const struct bfs_super_block *super)
6671f505522Stsutsui {
6681f505522Stsutsui
6691f505522Stsutsui return super->header.magic == BFS_MAGIC;
6701f505522Stsutsui }
6711f505522Stsutsui
672712239e3Sthorpej bool
bfs_dump(const struct bfs * bfs)6731f505522Stsutsui bfs_dump(const struct bfs *bfs)
6741f505522Stsutsui {
6751f505522Stsutsui const struct bfs_super_block_header *h;
6761f505522Stsutsui const struct bfs_compaction *compaction;
6771f505522Stsutsui const struct bfs_inode *inode;
6781f505522Stsutsui struct bfs_dirent *file;
6796bfe6be4Smartin int i, j, s, e;
6806bfe6be4Smartin size_t bytes;
6811f505522Stsutsui
6821f505522Stsutsui if (!bfs_superblock_valid(bfs->super_block)) {
6831f505522Stsutsui DPRINTF(bfs->debug, "invalid bfs super block.\n");
6844f3d5a9cSthorpej return false;
6851f505522Stsutsui }
6861f505522Stsutsui h = &bfs->super_block->header;
6871f505522Stsutsui compaction = &bfs->super_block->compaction;
6881f505522Stsutsui
6896bfe6be4Smartin DPRINTF(bfs->debug, "super block %zdbyte, inode %zdbyte, dirent %zdbyte\n",
6901f505522Stsutsui sizeof *bfs->super_block, sizeof *inode, sizeof *file);
6911f505522Stsutsui
6921f505522Stsutsui DPRINTF(bfs->debug, "magic=%x\n", h->magic);
6931f505522Stsutsui DPRINTF(bfs->debug, "data_start_byte=0x%x\n", h->data_start_byte);
6941f505522Stsutsui DPRINTF(bfs->debug, "data_end_byte=0x%x\n", h->data_end_byte);
6951f505522Stsutsui DPRINTF(bfs->debug, "from=%#x\n", compaction->from);
6961f505522Stsutsui DPRINTF(bfs->debug, "to=%#x\n", compaction->to);
6971f505522Stsutsui DPRINTF(bfs->debug, "from_backup=%#x\n", compaction->from_backup);
6981f505522Stsutsui DPRINTF(bfs->debug, "to_backup=%#x\n", compaction->to_backup);
6991f505522Stsutsui DPRINTF(bfs->debug, "fsname=%s\n", bfs->super_block->fsname);
7001f505522Stsutsui DPRINTF(bfs->debug, "volume=%s\n", bfs->super_block->volume);
7011f505522Stsutsui
7021f505522Stsutsui /* inode list */
7031f505522Stsutsui DPRINTF(bfs->debug, "[inode index list]\n");
7041f505522Stsutsui for (inode = bfs->inode, i = j = 0; i < bfs->max_inode; inode++, i++) {
7051f505522Stsutsui if (inode->number != 0) {
7061f505522Stsutsui const struct bfs_fileattr *attr = &inode->attr;
7071f505522Stsutsui DPRINTF(bfs->debug, "%3d %8d %8d %8d (%d) ",
7081f505522Stsutsui inode->number,
7091f505522Stsutsui inode->eof_offset_byte -
7101f505522Stsutsui (inode->start_sector * DEV_BSIZE) + 1,/* file size*/
7111f505522Stsutsui inode->start_sector,
7121f505522Stsutsui inode->end_sector, i);
7131f505522Stsutsui
7141f505522Stsutsui DPRINTF(bfs->debug, "%d %d %d %d %d %08x %08x %08x\n",
7151f505522Stsutsui attr->type, attr->mode, attr->uid, attr->gid,
7161f505522Stsutsui attr->nlink, attr->atime, attr->mtime, attr->ctime);
7171f505522Stsutsui j++;
7181f505522Stsutsui }
7191f505522Stsutsui }
7201f505522Stsutsui if (j != bfs->n_inode) {
7211f505522Stsutsui DPRINTF(bfs->debug, "inconsistent cached data. (i-node)\n");
7224f3d5a9cSthorpej return false;
7231f505522Stsutsui }
7241f505522Stsutsui DPRINTF(bfs->debug, "total %d i-node.\n", j);
7251f505522Stsutsui
7261f505522Stsutsui /* file list */
7271f505522Stsutsui DPRINTF(bfs->debug, "[dirent index list]\n");
7281f505522Stsutsui DPRINTF(bfs->debug, "%d file entries.\n", bfs->max_dirent);
7291f505522Stsutsui file = bfs->dirent;
7301f505522Stsutsui for (i = j = 0; i < bfs->max_dirent; i++, file++) {
7311f505522Stsutsui if (file->inode != 0) {
7321f505522Stsutsui if (bfs_file_lookup(bfs, file->name, &s, &e, &bytes))
7336bfe6be4Smartin DPRINTF(bfs->debug, "%3d %14s %8d %8d %8zd\n",
7341f505522Stsutsui file->inode, file->name, s, e, bytes);
7351f505522Stsutsui j++;
7361f505522Stsutsui }
7371f505522Stsutsui }
7381f505522Stsutsui if (j != bfs->n_dirent) {
7391f505522Stsutsui DPRINTF(bfs->debug, "inconsistent cached data. (dirent)\n");
7404f3d5a9cSthorpej return false;
7411f505522Stsutsui }
7421f505522Stsutsui DPRINTF(bfs->debug, "%d files.\n", j);
7431f505522Stsutsui
7444f3d5a9cSthorpej return true;
7451f505522Stsutsui }
746