xref: /netbsd-src/sys/fs/v7fs/v7fs_file_util.c (revision 514b0270dd0ac6e8ffce7a47d2bc570d815599f3)
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