1*514b0270Shannken /* $NetBSD: v7fs_file_util.c,v 1.5 2022/02/11 10:55:15 hannken Exp $ */
29255b46fSuch
39255b46fSuch /*-
49255b46fSuch * Copyright (c) 2011 The NetBSD Foundation, Inc.
59255b46fSuch * All rights reserved.
69255b46fSuch *
79255b46fSuch * This code is derived from software contributed to The NetBSD Foundation
89255b46fSuch * by UCHIYAMA Yasushi.
99255b46fSuch *
109255b46fSuch * Redistribution and use in source and binary forms, with or without
119255b46fSuch * modification, are permitted provided that the following conditions
129255b46fSuch * are met:
139255b46fSuch * 1. Redistributions of source code must retain the above copyright
149255b46fSuch * notice, this list of conditions and the following disclaimer.
159255b46fSuch * 2. Redistributions in binary form must reproduce the above copyright
169255b46fSuch * notice, this list of conditions and the following disclaimer in the
179255b46fSuch * documentation and/or other materials provided with the distribution.
189255b46fSuch *
199255b46fSuch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209255b46fSuch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219255b46fSuch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229255b46fSuch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239255b46fSuch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249255b46fSuch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259255b46fSuch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269255b46fSuch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279255b46fSuch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289255b46fSuch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299255b46fSuch * POSSIBILITY OF SUCH DAMAGE.
309255b46fSuch */
319255b46fSuch
32f1ca1ce2Sapb #if HAVE_NBTOOL_CONFIG_H
33f1ca1ce2Sapb #include "nbtool_config.h"
34f1ca1ce2Sapb #endif
35f1ca1ce2Sapb
369255b46fSuch #include <sys/cdefs.h>
37*514b0270Shannken __KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.5 2022/02/11 10:55:15 hannken Exp $");
389255b46fSuch #ifdef _KERNEL
399255b46fSuch #include <sys/systm.h>
409255b46fSuch #include <sys/param.h>
419255b46fSuch #else
429255b46fSuch #include <stdio.h>
439255b46fSuch #include <string.h>
449255b46fSuch #include <errno.h>
459255b46fSuch #endif
469255b46fSuch
479255b46fSuch #include "v7fs.h"
489255b46fSuch #include "v7fs_impl.h"
499255b46fSuch #include "v7fs_endian.h"
509255b46fSuch #include "v7fs_inode.h"
519255b46fSuch #include "v7fs_dirent.h"
529255b46fSuch #include "v7fs_file.h"
539255b46fSuch #include "v7fs_datablock.h"
549255b46fSuch
559255b46fSuch #ifdef V7FS_FILE_DEBUG
569255b46fSuch #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
579255b46fSuch #else
589255b46fSuch #define DPRINTF(fmt, args...) ((void)0)
599255b46fSuch #endif
609255b46fSuch
619255b46fSuch static int replace_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t);
629255b46fSuch static int lookup_by_number_subr(struct v7fs_self *, void *, v7fs_daddr_t,
639255b46fSuch size_t);
6453172ceaSuch static int can_dirmove(struct v7fs_self *, v7fs_ino_t, v7fs_ino_t);
6553172ceaSuch static int lookup_parent_from_dir_subr(struct v7fs_self *, void *,
6653172ceaSuch v7fs_daddr_t, size_t);
679255b46fSuch
689255b46fSuch int
v7fs_file_link(struct v7fs_self * fs,struct v7fs_inode * parent_dir,struct v7fs_inode * p,const char * name,size_t namelen)699255b46fSuch v7fs_file_link(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
70*514b0270Shannken struct v7fs_inode *p, const char *name, size_t namelen)
719255b46fSuch {
729255b46fSuch int error = 0;
739255b46fSuch
74*514b0270Shannken DPRINTF("%d %d %.*s\n", parent_dir->inode_number, p->inode_number,
75*514b0270Shannken (int)namelen, name);
769255b46fSuch if ((error = v7fs_directory_add_entry(fs, parent_dir, p->inode_number,
77*514b0270Shannken name, namelen))) {
789255b46fSuch DPRINTF("can't add entry");
799255b46fSuch return error;
809255b46fSuch }
819255b46fSuch p->nlink++;
829255b46fSuch v7fs_inode_writeback(fs, p);
839255b46fSuch
849255b46fSuch return 0;
859255b46fSuch }
869255b46fSuch
879255b46fSuch int
v7fs_file_symlink(struct v7fs_self * fs,struct v7fs_inode * p,const char * target)886a2dbe9aSuch v7fs_file_symlink(struct v7fs_self *fs, struct v7fs_inode *p,
896a2dbe9aSuch const char *target)
906a2dbe9aSuch {
916a2dbe9aSuch int error;
926a2dbe9aSuch size_t len = strlen(target) + 1;
936a2dbe9aSuch
946a2dbe9aSuch if (len > V7FSBSD_MAXSYMLINKLEN) {/* limited target 512byte pathname */
956a2dbe9aSuch DPRINTF("too long pathname.");
966a2dbe9aSuch return ENAMETOOLONG;
976a2dbe9aSuch }
986a2dbe9aSuch
996a2dbe9aSuch if ((error = v7fs_datablock_expand(fs, p, len))) {
1006a2dbe9aSuch return error;
1016a2dbe9aSuch }
1026a2dbe9aSuch
1036a2dbe9aSuch v7fs_daddr_t blk = p->addr[0]; /* 1block only. */
1046a2dbe9aSuch void *buf;
1056a2dbe9aSuch if (!(buf = scratch_read(fs, blk))) {
1066a2dbe9aSuch return EIO;
1076a2dbe9aSuch }
1086a2dbe9aSuch
1096a2dbe9aSuch strncpy(buf, target, V7FS_BSIZE);
1106a2dbe9aSuch if (!fs->io.write(fs->io.cookie, buf, blk)) {
1116a2dbe9aSuch scratch_free(fs, buf);
1126a2dbe9aSuch return EIO;
1136a2dbe9aSuch }
1146a2dbe9aSuch scratch_free(fs, buf);
1156a2dbe9aSuch v7fs_inode_writeback(fs, p);
1166a2dbe9aSuch
1176a2dbe9aSuch return 0;
1186a2dbe9aSuch }
1196a2dbe9aSuch
1206a2dbe9aSuch int
v7fs_file_rename(struct v7fs_self * fs,struct v7fs_inode * parent_from,const char * from,size_t fromlen,struct v7fs_inode * parent_to,const char * to,size_t tolen)1219255b46fSuch v7fs_file_rename(struct v7fs_self *fs, struct v7fs_inode *parent_from,
122*514b0270Shannken const char *from, size_t fromlen, struct v7fs_inode *parent_to,
123*514b0270Shannken const char *to, size_t tolen)
1249255b46fSuch {
1259255b46fSuch v7fs_ino_t from_ino, to_ino;
12653172ceaSuch struct v7fs_inode inode;
1279255b46fSuch int error;
12853172ceaSuch bool dir_move;
1299255b46fSuch
13053172ceaSuch /* Check source file */
131*514b0270Shannken if ((error = v7fs_file_lookup_by_name(fs, parent_from, from, fromlen,
1329255b46fSuch &from_ino))) {
133*514b0270Shannken DPRINTF("%.*s don't exists\n", (int)fromlen, from);
1349255b46fSuch return error;
1359255b46fSuch }
13653172ceaSuch v7fs_inode_load(fs, &inode, from_ino);
13753172ceaSuch dir_move = v7fs_inode_isdir(&inode);
1389255b46fSuch
13953172ceaSuch /* Check target file */
140*514b0270Shannken error = v7fs_file_lookup_by_name(fs, parent_to, to, tolen, &to_ino);
14153172ceaSuch if (error == 0) { /* found */
142*514b0270Shannken DPRINTF("%.*s already exists\n", (int)tolen, to);
143*514b0270Shannken if ((error = v7fs_file_deallocate(fs, parent_to, to, tolen))) {
144*514b0270Shannken DPRINTF("%.*s can't remove %d\n", (int)tolen,
145*514b0270Shannken to, error);
1469255b46fSuch return error;
1479255b46fSuch }
1489255b46fSuch } else if (error != ENOENT) {
1499255b46fSuch DPRINTF("error=%d\n", error);
1509255b46fSuch return error;
1519255b46fSuch }
15253172ceaSuch /* Check directory hierarchy. t_vnops rename_dir(5) */
15353172ceaSuch if (dir_move && (error = can_dirmove(fs, from_ino,
15453172ceaSuch parent_to->inode_number))) {
155*514b0270Shannken DPRINTF("dst '%.*s' is child dir of '%.*s'. error=%d\n",
156*514b0270Shannken (int)tolen, to, (int)fromlen, from, error);
15753172ceaSuch return error;
15853172ceaSuch }
1599255b46fSuch
160*514b0270Shannken if ((error = v7fs_directory_add_entry(fs, parent_to, from_ino, to,
161*514b0270Shannken tolen))) {
1629255b46fSuch DPRINTF("can't add entry");
1639255b46fSuch return error;
1649255b46fSuch }
1659255b46fSuch
166*514b0270Shannken if ((error = v7fs_directory_remove_entry(fs, parent_from, from,
167*514b0270Shannken fromlen))) {
1689255b46fSuch DPRINTF("can't remove entry");
1699255b46fSuch return error;
1709255b46fSuch }
1719255b46fSuch
17253172ceaSuch if (dir_move && (parent_from != parent_to)) {
1739255b46fSuch /* If directory move, update ".." */
17453172ceaSuch if ((error = v7fs_directory_replace_entry(fs, &inode, "..",
17553172ceaSuch parent_to->inode_number))) {
1769255b46fSuch DPRINTF("can't replace parent dir");
1779255b46fSuch return error;
1789255b46fSuch }
1799255b46fSuch v7fs_inode_writeback(fs, &inode);
1809255b46fSuch }
1819255b46fSuch
1829255b46fSuch return 0;
1839255b46fSuch }
1849255b46fSuch
1859255b46fSuch
1869255b46fSuch int
v7fs_directory_replace_entry(struct v7fs_self * fs,struct v7fs_inode * self_dir,const char * name,v7fs_ino_t ino)1879255b46fSuch v7fs_directory_replace_entry(struct v7fs_self *fs, struct v7fs_inode *self_dir,
1889255b46fSuch const char *name, v7fs_ino_t ino)
1899255b46fSuch {
1909255b46fSuch int error;
1919255b46fSuch
1929255b46fSuch /* Search entry that replaced. replace it to new inode number. */
1939255b46fSuch struct v7fs_lookup_arg lookup_arg = { .name = name,
1949255b46fSuch .inode_number = ino };
1959255b46fSuch if ((error = v7fs_datablock_foreach(fs, self_dir, replace_subr,
1969255b46fSuch &lookup_arg)) != V7FS_ITERATOR_BREAK)
1979255b46fSuch return ENOENT;
1989255b46fSuch
1999255b46fSuch return 0;
2009255b46fSuch }
2019255b46fSuch
2029255b46fSuch static int
replace_subr(struct v7fs_self * fs,void * ctx,v7fs_daddr_t blk,size_t sz)2039255b46fSuch replace_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
2049255b46fSuch {
2059255b46fSuch struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
2069255b46fSuch struct v7fs_dirent *dir;
2079255b46fSuch void *buf;
2089255b46fSuch size_t i, n;
2099255b46fSuch int ret = 0;
2109255b46fSuch
2119255b46fSuch DPRINTF("match start blk=%x\n", blk);
2129255b46fSuch if (!(buf = scratch_read(fs, blk)))
2139255b46fSuch return EIO;
2149255b46fSuch
2159255b46fSuch dir = (struct v7fs_dirent *)buf;
2169255b46fSuch n = sz / sizeof(*dir);
2179255b46fSuch
2189255b46fSuch for (i = 0; i < n; i++, dir++) { /*disk endian */
2199255b46fSuch if (strncmp(p->name, (const char *)dir->name, V7FS_NAME_MAX)
2209255b46fSuch == 0) {
2219255b46fSuch /* Replace inode# */
2229255b46fSuch dir->inode_number = V7FS_VAL16(fs, p->inode_number);
2239255b46fSuch /* Write back. */
2249255b46fSuch if (!fs->io.write(fs->io.cookie, buf, blk))
2259255b46fSuch ret = EIO;
2269255b46fSuch else
2279255b46fSuch ret = V7FS_ITERATOR_BREAK;
2289255b46fSuch break;
2299255b46fSuch }
2309255b46fSuch }
2319255b46fSuch scratch_free(fs, buf);
2329255b46fSuch
2339255b46fSuch return ret;
2349255b46fSuch }
2359255b46fSuch
2369255b46fSuch bool
v7fs_file_lookup_by_number(struct v7fs_self * fs,struct v7fs_inode * parent_dir,v7fs_ino_t ino,char * buf)2379255b46fSuch v7fs_file_lookup_by_number(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
2389255b46fSuch v7fs_ino_t ino, char *buf)
2399255b46fSuch {
2409255b46fSuch int ret;
2419255b46fSuch
2429255b46fSuch ret = v7fs_datablock_foreach(fs, parent_dir, lookup_by_number_subr,
2439255b46fSuch &(struct v7fs_lookup_arg){ .inode_number = ino, .buf = buf });
2449255b46fSuch
2459255b46fSuch return ret == V7FS_ITERATOR_BREAK;
2469255b46fSuch }
2479255b46fSuch
2489255b46fSuch static int
lookup_by_number_subr(struct v7fs_self * fs,void * ctx,v7fs_daddr_t blk,size_t sz)2499255b46fSuch lookup_by_number_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk,
2509255b46fSuch size_t sz)
2519255b46fSuch {
2529255b46fSuch struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
2539255b46fSuch struct v7fs_dirent *dir;
2549255b46fSuch void *buf;
2559255b46fSuch size_t i, n;
2569255b46fSuch int ret = 0;
2579255b46fSuch
2589255b46fSuch if (!(buf = scratch_read(fs, blk)))
2599255b46fSuch return EIO;
2609255b46fSuch
2619255b46fSuch dir = (struct v7fs_dirent *)buf;
2629255b46fSuch n = sz / sizeof(*dir);
2639255b46fSuch v7fs_dirent_endian_convert(fs, dir, n);
2649255b46fSuch
2659255b46fSuch for (i = 0; i < n; i++, dir++) {
2669255b46fSuch if (dir->inode_number == p->inode_number) {
2679255b46fSuch if (p->buf)
268*514b0270Shannken v7fs_dirent_filename(p->buf, dir->name,
269*514b0270Shannken strlen(dir->name));
2709255b46fSuch ret = V7FS_ITERATOR_BREAK;
2719255b46fSuch break;
2729255b46fSuch }
2739255b46fSuch }
2749255b46fSuch scratch_free(fs, buf);
2759255b46fSuch
2769255b46fSuch return ret;
2779255b46fSuch }
27853172ceaSuch
27953172ceaSuch struct lookup_parent_arg {
28053172ceaSuch v7fs_ino_t parent_ino;
28153172ceaSuch };
28253172ceaSuch
28353172ceaSuch static int
can_dirmove(struct v7fs_self * fs,v7fs_ino_t from_ino,v7fs_ino_t to_ino)28453172ceaSuch can_dirmove(struct v7fs_self *fs, v7fs_ino_t from_ino, v7fs_ino_t to_ino)
28553172ceaSuch {
28653172ceaSuch struct v7fs_inode inode;
28753172ceaSuch v7fs_ino_t parent;
28853172ceaSuch int error;
28953172ceaSuch
29053172ceaSuch /* Start dir. */
29153172ceaSuch if ((error = v7fs_inode_load(fs, &inode, to_ino)))
29253172ceaSuch return error;
29353172ceaSuch
29453172ceaSuch if (!v7fs_inode_isdir(&inode))
29553172ceaSuch return ENOTDIR;
29653172ceaSuch
29753172ceaSuch /* Lookup the parent. */
29853172ceaSuch do {
29953172ceaSuch struct lookup_parent_arg arg;
30053172ceaSuch /* Search parent dir */
30153172ceaSuch arg.parent_ino = 0;
30253172ceaSuch v7fs_datablock_foreach(fs, &inode, lookup_parent_from_dir_subr,
30353172ceaSuch &arg);
30453172ceaSuch if ((parent = arg.parent_ino) == 0) {
30553172ceaSuch DPRINTF("***parent missing\n");
30653172ceaSuch return ENOENT;
30753172ceaSuch }
30853172ceaSuch /* Load parent dir */
30953172ceaSuch if ((error = v7fs_inode_load(fs, &inode, parent)))
31053172ceaSuch return error;
31153172ceaSuch if (parent == from_ino) {
31253172ceaSuch DPRINTF("#%d is child dir of #%d\n", to_ino, from_ino);
31353172ceaSuch return EINVAL;
31453172ceaSuch }
31553172ceaSuch } while (parent != V7FS_ROOT_INODE);
31653172ceaSuch
31753172ceaSuch return 0;
31853172ceaSuch }
31953172ceaSuch
32053172ceaSuch static int
lookup_parent_from_dir_subr(struct v7fs_self * fs,void * ctx,v7fs_daddr_t blk,size_t sz)32153172ceaSuch lookup_parent_from_dir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk,
32253172ceaSuch size_t sz)
32353172ceaSuch {
32453172ceaSuch struct lookup_parent_arg *arg = (struct lookup_parent_arg *)ctx;
32553172ceaSuch char name[V7FS_NAME_MAX + 1];
32653172ceaSuch void *buf;
32753172ceaSuch int ret = 0;
32853172ceaSuch
32953172ceaSuch if (!(buf = scratch_read(fs, blk)))
33053172ceaSuch return 0;
33153172ceaSuch struct v7fs_dirent *dir = (struct v7fs_dirent *)buf;
33253172ceaSuch size_t i, n = sz / sizeof(*dir);
33353172ceaSuch if (!v7fs_dirent_endian_convert(fs, dir, n)) {
33453172ceaSuch scratch_free(fs, buf);
33553172ceaSuch return V7FS_ITERATOR_ERROR;
33653172ceaSuch }
33753172ceaSuch
33853172ceaSuch for (i = 0; i < n; i++, dir++) {
339*514b0270Shannken v7fs_dirent_filename(name, dir->name, strlen(dir->name));
34053172ceaSuch if (strncmp(dir->name, "..", V7FS_NAME_MAX) != 0)
34153172ceaSuch continue;
34253172ceaSuch
34353172ceaSuch arg->parent_ino = dir->inode_number;
34453172ceaSuch ret = V7FS_ITERATOR_BREAK;
34553172ceaSuch break;
34653172ceaSuch }
34753172ceaSuch
34853172ceaSuch scratch_free(fs, buf);
34953172ceaSuch return ret;
35053172ceaSuch }
351