xref: /minix3/sys/fs/v7fs/v7fs_file_util.c (revision 9f988b79349f9b89ecc822458c30ec8897558560)
1*9f988b79SJean-Baptiste Boric /*	$NetBSD: v7fs_file_util.c,v 1.4 2011/07/30 03:52:04 uch Exp $	*/
2*9f988b79SJean-Baptiste Boric 
3*9f988b79SJean-Baptiste Boric /*-
4*9f988b79SJean-Baptiste Boric  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5*9f988b79SJean-Baptiste Boric  * All rights reserved.
6*9f988b79SJean-Baptiste Boric  *
7*9f988b79SJean-Baptiste Boric  * This code is derived from software contributed to The NetBSD Foundation
8*9f988b79SJean-Baptiste Boric  * by UCHIYAMA Yasushi.
9*9f988b79SJean-Baptiste Boric  *
10*9f988b79SJean-Baptiste Boric  * Redistribution and use in source and binary forms, with or without
11*9f988b79SJean-Baptiste Boric  * modification, are permitted provided that the following conditions
12*9f988b79SJean-Baptiste Boric  * are met:
13*9f988b79SJean-Baptiste Boric  * 1. Redistributions of source code must retain the above copyright
14*9f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer.
15*9f988b79SJean-Baptiste Boric  * 2. Redistributions in binary form must reproduce the above copyright
16*9f988b79SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer in the
17*9f988b79SJean-Baptiste Boric  *    documentation and/or other materials provided with the distribution.
18*9f988b79SJean-Baptiste Boric  *
19*9f988b79SJean-Baptiste Boric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*9f988b79SJean-Baptiste Boric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*9f988b79SJean-Baptiste Boric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*9f988b79SJean-Baptiste Boric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*9f988b79SJean-Baptiste Boric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*9f988b79SJean-Baptiste Boric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*9f988b79SJean-Baptiste Boric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*9f988b79SJean-Baptiste Boric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*9f988b79SJean-Baptiste Boric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*9f988b79SJean-Baptiste Boric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*9f988b79SJean-Baptiste Boric  * POSSIBILITY OF SUCH DAMAGE.
30*9f988b79SJean-Baptiste Boric  */
31*9f988b79SJean-Baptiste Boric 
32*9f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
33*9f988b79SJean-Baptiste Boric #include "nbtool_config.h"
34*9f988b79SJean-Baptiste Boric #endif
35*9f988b79SJean-Baptiste Boric 
36*9f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
37*9f988b79SJean-Baptiste Boric __KERNEL_RCSID(0, "$NetBSD: v7fs_file_util.c,v 1.4 2011/07/30 03:52:04 uch Exp $");
38*9f988b79SJean-Baptiste Boric #ifdef _KERNEL
39*9f988b79SJean-Baptiste Boric #include <sys/systm.h>
40*9f988b79SJean-Baptiste Boric #include <sys/param.h>
41*9f988b79SJean-Baptiste Boric #else
42*9f988b79SJean-Baptiste Boric #include <stdio.h>
43*9f988b79SJean-Baptiste Boric #include <string.h>
44*9f988b79SJean-Baptiste Boric #include <errno.h>
45*9f988b79SJean-Baptiste Boric #endif
46*9f988b79SJean-Baptiste Boric 
47*9f988b79SJean-Baptiste Boric #include "v7fs.h"
48*9f988b79SJean-Baptiste Boric #include "v7fs_impl.h"
49*9f988b79SJean-Baptiste Boric #include "v7fs_endian.h"
50*9f988b79SJean-Baptiste Boric #include "v7fs_inode.h"
51*9f988b79SJean-Baptiste Boric #include "v7fs_dirent.h"
52*9f988b79SJean-Baptiste Boric #include "v7fs_file.h"
53*9f988b79SJean-Baptiste Boric #include "v7fs_datablock.h"
54*9f988b79SJean-Baptiste Boric 
55*9f988b79SJean-Baptiste Boric #ifdef V7FS_FILE_DEBUG
56*9f988b79SJean-Baptiste Boric #define	DPRINTF(fmt, args...)	printf("%s: " fmt, __func__, ##args)
57*9f988b79SJean-Baptiste Boric #else
58*9f988b79SJean-Baptiste Boric #define	DPRINTF(fmt, args...)	((void)0)
59*9f988b79SJean-Baptiste Boric #endif
60*9f988b79SJean-Baptiste Boric 
61*9f988b79SJean-Baptiste Boric static int replace_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t);
62*9f988b79SJean-Baptiste Boric static int lookup_by_number_subr(struct v7fs_self *, void *, v7fs_daddr_t,
63*9f988b79SJean-Baptiste Boric     size_t);
64*9f988b79SJean-Baptiste Boric static int can_dirmove(struct v7fs_self *, v7fs_ino_t, v7fs_ino_t);
65*9f988b79SJean-Baptiste Boric static int lookup_parent_from_dir_subr(struct v7fs_self *, void *,
66*9f988b79SJean-Baptiste Boric     v7fs_daddr_t, size_t);
67*9f988b79SJean-Baptiste Boric 
68*9f988b79SJean-Baptiste Boric int
v7fs_file_link(struct v7fs_self * fs,struct v7fs_inode * parent_dir,struct v7fs_inode * p,const char * name)69*9f988b79SJean-Baptiste Boric v7fs_file_link(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
70*9f988b79SJean-Baptiste Boric     struct v7fs_inode *p, const char *name)
71*9f988b79SJean-Baptiste Boric {
72*9f988b79SJean-Baptiste Boric 	int error = 0;
73*9f988b79SJean-Baptiste Boric 
74*9f988b79SJean-Baptiste Boric 	DPRINTF("%d %d %s\n", parent_dir->inode_number, p->inode_number, name);
75*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_directory_add_entry(fs, parent_dir, p->inode_number,
76*9f988b79SJean-Baptiste Boric 	    name))) {
77*9f988b79SJean-Baptiste Boric 		DPRINTF("can't add entry");
78*9f988b79SJean-Baptiste Boric 		return error;
79*9f988b79SJean-Baptiste Boric 	}
80*9f988b79SJean-Baptiste Boric 	p->nlink++;
81*9f988b79SJean-Baptiste Boric 	v7fs_inode_writeback(fs, p);
82*9f988b79SJean-Baptiste Boric 
83*9f988b79SJean-Baptiste Boric 	return 0;
84*9f988b79SJean-Baptiste Boric }
85*9f988b79SJean-Baptiste Boric 
86*9f988b79SJean-Baptiste Boric int
v7fs_file_symlink(struct v7fs_self * fs,struct v7fs_inode * p,const char * target)87*9f988b79SJean-Baptiste Boric v7fs_file_symlink(struct v7fs_self *fs, struct v7fs_inode *p,
88*9f988b79SJean-Baptiste Boric     const char *target)
89*9f988b79SJean-Baptiste Boric {
90*9f988b79SJean-Baptiste Boric 	int error;
91*9f988b79SJean-Baptiste Boric 	size_t len = strlen(target) + 1;
92*9f988b79SJean-Baptiste Boric 
93*9f988b79SJean-Baptiste Boric 	if (len > V7FSBSD_MAXSYMLINKLEN) {/* limited target 512byte pathname */
94*9f988b79SJean-Baptiste Boric 		DPRINTF("too long pathname.");
95*9f988b79SJean-Baptiste Boric 		return ENAMETOOLONG;
96*9f988b79SJean-Baptiste Boric 	}
97*9f988b79SJean-Baptiste Boric 
98*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_datablock_expand(fs, p, len))) {
99*9f988b79SJean-Baptiste Boric 		return error;
100*9f988b79SJean-Baptiste Boric 	}
101*9f988b79SJean-Baptiste Boric 
102*9f988b79SJean-Baptiste Boric 	v7fs_daddr_t blk = p->addr[0];	/* 1block only.  */
103*9f988b79SJean-Baptiste Boric 	void *buf;
104*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, blk))) {
105*9f988b79SJean-Baptiste Boric 		return EIO;
106*9f988b79SJean-Baptiste Boric 	}
107*9f988b79SJean-Baptiste Boric 
108*9f988b79SJean-Baptiste Boric 	strncpy(buf, target, V7FS_BSIZE);
109*9f988b79SJean-Baptiste Boric 	if (!fs->io.write(fs->io.cookie, buf, blk)) {
110*9f988b79SJean-Baptiste Boric 		scratch_free(fs, buf);
111*9f988b79SJean-Baptiste Boric 		return EIO;
112*9f988b79SJean-Baptiste Boric 	}
113*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
114*9f988b79SJean-Baptiste Boric 	v7fs_inode_writeback(fs, p);
115*9f988b79SJean-Baptiste Boric 
116*9f988b79SJean-Baptiste Boric 	return 0;
117*9f988b79SJean-Baptiste Boric }
118*9f988b79SJean-Baptiste Boric 
119*9f988b79SJean-Baptiste Boric int
v7fs_file_rename(struct v7fs_self * fs,struct v7fs_inode * parent_from,const char * from,struct v7fs_inode * parent_to,const char * to)120*9f988b79SJean-Baptiste Boric v7fs_file_rename(struct v7fs_self *fs, struct v7fs_inode *parent_from,
121*9f988b79SJean-Baptiste Boric     const char *from, struct v7fs_inode *parent_to, const char *to)
122*9f988b79SJean-Baptiste Boric {
123*9f988b79SJean-Baptiste Boric 	v7fs_ino_t from_ino, to_ino;
124*9f988b79SJean-Baptiste Boric 	struct v7fs_inode inode;
125*9f988b79SJean-Baptiste Boric 	int error;
126*9f988b79SJean-Baptiste Boric 	bool dir_move;
127*9f988b79SJean-Baptiste Boric 
128*9f988b79SJean-Baptiste Boric 	/* Check source file */
129*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_file_lookup_by_name(fs, parent_from, from,
130*9f988b79SJean-Baptiste Boric 	    &from_ino))) {
131*9f988b79SJean-Baptiste Boric 		DPRINTF("%s don't exists\n", from);
132*9f988b79SJean-Baptiste Boric 		return error;
133*9f988b79SJean-Baptiste Boric 	}
134*9f988b79SJean-Baptiste Boric 	v7fs_inode_load(fs, &inode, from_ino);
135*9f988b79SJean-Baptiste Boric 	dir_move = v7fs_inode_isdir(&inode);
136*9f988b79SJean-Baptiste Boric 
137*9f988b79SJean-Baptiste Boric 	/* Check target file */
138*9f988b79SJean-Baptiste Boric 	error = v7fs_file_lookup_by_name(fs, parent_to, to, &to_ino);
139*9f988b79SJean-Baptiste Boric 	if (error == 0) {	/* found */
140*9f988b79SJean-Baptiste Boric 		DPRINTF("%s already exists\n", to);
141*9f988b79SJean-Baptiste Boric 		if ((error = v7fs_file_deallocate(fs, parent_to, to))) {
142*9f988b79SJean-Baptiste Boric 			DPRINTF("%s can't remove %d\n", to, error);
143*9f988b79SJean-Baptiste Boric 			return error;
144*9f988b79SJean-Baptiste Boric 		}
145*9f988b79SJean-Baptiste Boric 	} else if (error != ENOENT) {
146*9f988b79SJean-Baptiste Boric 		DPRINTF("error=%d\n", error);
147*9f988b79SJean-Baptiste Boric 		return error;
148*9f988b79SJean-Baptiste Boric 	}
149*9f988b79SJean-Baptiste Boric 	/* Check directory hierarchy. t_vnops rename_dir(5) */
150*9f988b79SJean-Baptiste Boric 	if (dir_move && (error = can_dirmove(fs, from_ino,
151*9f988b79SJean-Baptiste Boric 	    parent_to->inode_number))) {
152*9f988b79SJean-Baptiste Boric 		DPRINTF("dst '%s' is child dir of '%s'. error=%d\n", to, from,
153*9f988b79SJean-Baptiste Boric 		    error);
154*9f988b79SJean-Baptiste Boric 		return error;
155*9f988b79SJean-Baptiste Boric 	}
156*9f988b79SJean-Baptiste Boric 
157*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_directory_add_entry(fs, parent_to, from_ino, to))) {
158*9f988b79SJean-Baptiste Boric 		DPRINTF("can't add entry");
159*9f988b79SJean-Baptiste Boric 		return error;
160*9f988b79SJean-Baptiste Boric 	}
161*9f988b79SJean-Baptiste Boric 
162*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_directory_remove_entry(fs, parent_from, from))) {
163*9f988b79SJean-Baptiste Boric 		DPRINTF("can't remove entry");
164*9f988b79SJean-Baptiste Boric 		return error;
165*9f988b79SJean-Baptiste Boric 	}
166*9f988b79SJean-Baptiste Boric 
167*9f988b79SJean-Baptiste Boric 	if (dir_move && (parent_from != parent_to)) {
168*9f988b79SJean-Baptiste Boric 		/* If directory move, update ".." */
169*9f988b79SJean-Baptiste Boric 		if ((error = v7fs_directory_replace_entry(fs, &inode, "..",
170*9f988b79SJean-Baptiste Boric 			    parent_to->inode_number))) {
171*9f988b79SJean-Baptiste Boric 			DPRINTF("can't replace parent dir");
172*9f988b79SJean-Baptiste Boric 			return error;
173*9f988b79SJean-Baptiste Boric 		}
174*9f988b79SJean-Baptiste Boric 		v7fs_inode_writeback(fs, &inode);
175*9f988b79SJean-Baptiste Boric 	}
176*9f988b79SJean-Baptiste Boric 
177*9f988b79SJean-Baptiste Boric 	return 0;
178*9f988b79SJean-Baptiste Boric }
179*9f988b79SJean-Baptiste Boric 
180*9f988b79SJean-Baptiste Boric 
181*9f988b79SJean-Baptiste Boric int
v7fs_directory_replace_entry(struct v7fs_self * fs,struct v7fs_inode * self_dir,const char * name,v7fs_ino_t ino)182*9f988b79SJean-Baptiste Boric v7fs_directory_replace_entry(struct v7fs_self *fs,  struct v7fs_inode *self_dir,
183*9f988b79SJean-Baptiste Boric     const char *name, v7fs_ino_t ino)
184*9f988b79SJean-Baptiste Boric {
185*9f988b79SJean-Baptiste Boric 	int error;
186*9f988b79SJean-Baptiste Boric 
187*9f988b79SJean-Baptiste Boric 	/* Search entry that replaced. replace it to new inode number. */
188*9f988b79SJean-Baptiste Boric 	struct v7fs_lookup_arg lookup_arg = { .name = name,
189*9f988b79SJean-Baptiste Boric 					      .inode_number = ino };
190*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_datablock_foreach(fs, self_dir, replace_subr,
191*9f988b79SJean-Baptiste Boric 	    &lookup_arg)) != V7FS_ITERATOR_BREAK)
192*9f988b79SJean-Baptiste Boric 		return ENOENT;
193*9f988b79SJean-Baptiste Boric 
194*9f988b79SJean-Baptiste Boric 	return 0;
195*9f988b79SJean-Baptiste Boric }
196*9f988b79SJean-Baptiste Boric 
197*9f988b79SJean-Baptiste Boric static int
replace_subr(struct v7fs_self * fs,void * ctx,v7fs_daddr_t blk,size_t sz)198*9f988b79SJean-Baptiste Boric replace_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
199*9f988b79SJean-Baptiste Boric {
200*9f988b79SJean-Baptiste Boric 	struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
201*9f988b79SJean-Baptiste Boric 	struct v7fs_dirent *dir;
202*9f988b79SJean-Baptiste Boric 	void *buf;
203*9f988b79SJean-Baptiste Boric 	size_t i, n;
204*9f988b79SJean-Baptiste Boric 	int ret = 0;
205*9f988b79SJean-Baptiste Boric 
206*9f988b79SJean-Baptiste Boric 	DPRINTF("match start blk=%x\n", blk);
207*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, blk)))
208*9f988b79SJean-Baptiste Boric 		return EIO;
209*9f988b79SJean-Baptiste Boric 
210*9f988b79SJean-Baptiste Boric 	dir = (struct v7fs_dirent *)buf;
211*9f988b79SJean-Baptiste Boric 	n = sz / sizeof(*dir);
212*9f988b79SJean-Baptiste Boric 
213*9f988b79SJean-Baptiste Boric 	for (i = 0; i < n; i++, dir++) { /*disk endian */
214*9f988b79SJean-Baptiste Boric 		if (strncmp(p->name, (const char *)dir->name, V7FS_NAME_MAX)
215*9f988b79SJean-Baptiste Boric 		    == 0) {
216*9f988b79SJean-Baptiste Boric 			/* Replace inode# */
217*9f988b79SJean-Baptiste Boric 			dir->inode_number = V7FS_VAL16(fs, p->inode_number);
218*9f988b79SJean-Baptiste Boric 			/* Write back. */
219*9f988b79SJean-Baptiste Boric 			if (!fs->io.write(fs->io.cookie, buf, blk))
220*9f988b79SJean-Baptiste Boric 				ret = EIO;
221*9f988b79SJean-Baptiste Boric 			else
222*9f988b79SJean-Baptiste Boric 				ret = V7FS_ITERATOR_BREAK;
223*9f988b79SJean-Baptiste Boric 			break;
224*9f988b79SJean-Baptiste Boric 		}
225*9f988b79SJean-Baptiste Boric 	}
226*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
227*9f988b79SJean-Baptiste Boric 
228*9f988b79SJean-Baptiste Boric 	return ret;
229*9f988b79SJean-Baptiste Boric }
230*9f988b79SJean-Baptiste Boric 
231*9f988b79SJean-Baptiste Boric bool
v7fs_file_lookup_by_number(struct v7fs_self * fs,struct v7fs_inode * parent_dir,v7fs_ino_t ino,char * buf)232*9f988b79SJean-Baptiste Boric v7fs_file_lookup_by_number(struct v7fs_self *fs, struct v7fs_inode *parent_dir,
233*9f988b79SJean-Baptiste Boric     v7fs_ino_t ino, char *buf)
234*9f988b79SJean-Baptiste Boric {
235*9f988b79SJean-Baptiste Boric 	int ret;
236*9f988b79SJean-Baptiste Boric 
237*9f988b79SJean-Baptiste Boric 	ret = v7fs_datablock_foreach(fs, parent_dir, lookup_by_number_subr,
238*9f988b79SJean-Baptiste Boric 	    &(struct v7fs_lookup_arg){ .inode_number = ino, .buf = buf });
239*9f988b79SJean-Baptiste Boric 
240*9f988b79SJean-Baptiste Boric 	return ret == V7FS_ITERATOR_BREAK;
241*9f988b79SJean-Baptiste Boric }
242*9f988b79SJean-Baptiste Boric 
243*9f988b79SJean-Baptiste Boric static int
lookup_by_number_subr(struct v7fs_self * fs,void * ctx,v7fs_daddr_t blk,size_t sz)244*9f988b79SJean-Baptiste Boric lookup_by_number_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk,
245*9f988b79SJean-Baptiste Boric     size_t sz)
246*9f988b79SJean-Baptiste Boric {
247*9f988b79SJean-Baptiste Boric 	struct v7fs_lookup_arg *p = (struct v7fs_lookup_arg *)ctx;
248*9f988b79SJean-Baptiste Boric 	struct v7fs_dirent *dir;
249*9f988b79SJean-Baptiste Boric 	void *buf;
250*9f988b79SJean-Baptiste Boric 	size_t i, n;
251*9f988b79SJean-Baptiste Boric 	int ret = 0;
252*9f988b79SJean-Baptiste Boric 
253*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, blk)))
254*9f988b79SJean-Baptiste Boric 		return EIO;
255*9f988b79SJean-Baptiste Boric 
256*9f988b79SJean-Baptiste Boric 	dir = (struct v7fs_dirent *)buf;
257*9f988b79SJean-Baptiste Boric 	n = sz / sizeof(*dir);
258*9f988b79SJean-Baptiste Boric 	v7fs_dirent_endian_convert(fs, dir, n);
259*9f988b79SJean-Baptiste Boric 
260*9f988b79SJean-Baptiste Boric 	for (i = 0; i < n; i++, dir++) {
261*9f988b79SJean-Baptiste Boric 		if (dir->inode_number == p->inode_number) {
262*9f988b79SJean-Baptiste Boric 			if (p->buf)
263*9f988b79SJean-Baptiste Boric 				v7fs_dirent_filename(p->buf, dir->name);
264*9f988b79SJean-Baptiste Boric 			ret = V7FS_ITERATOR_BREAK;
265*9f988b79SJean-Baptiste Boric 			break;
266*9f988b79SJean-Baptiste Boric 		}
267*9f988b79SJean-Baptiste Boric 	}
268*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
269*9f988b79SJean-Baptiste Boric 
270*9f988b79SJean-Baptiste Boric 	return ret;
271*9f988b79SJean-Baptiste Boric }
272*9f988b79SJean-Baptiste Boric 
273*9f988b79SJean-Baptiste Boric struct lookup_parent_arg {
274*9f988b79SJean-Baptiste Boric 	v7fs_ino_t parent_ino;
275*9f988b79SJean-Baptiste Boric };
276*9f988b79SJean-Baptiste Boric 
277*9f988b79SJean-Baptiste Boric static int
can_dirmove(struct v7fs_self * fs,v7fs_ino_t from_ino,v7fs_ino_t to_ino)278*9f988b79SJean-Baptiste Boric can_dirmove(struct v7fs_self *fs, v7fs_ino_t from_ino, v7fs_ino_t to_ino)
279*9f988b79SJean-Baptiste Boric {
280*9f988b79SJean-Baptiste Boric 	struct v7fs_inode inode;
281*9f988b79SJean-Baptiste Boric 	v7fs_ino_t parent;
282*9f988b79SJean-Baptiste Boric 	int error;
283*9f988b79SJean-Baptiste Boric 
284*9f988b79SJean-Baptiste Boric 	/* Start dir. */
285*9f988b79SJean-Baptiste Boric 	if ((error = v7fs_inode_load(fs, &inode, to_ino)))
286*9f988b79SJean-Baptiste Boric 		return error;
287*9f988b79SJean-Baptiste Boric 
288*9f988b79SJean-Baptiste Boric 	if (!v7fs_inode_isdir(&inode))
289*9f988b79SJean-Baptiste Boric 		return ENOTDIR;
290*9f988b79SJean-Baptiste Boric 
291*9f988b79SJean-Baptiste Boric 	/* Lookup the parent. */
292*9f988b79SJean-Baptiste Boric 	do {
293*9f988b79SJean-Baptiste Boric 		struct lookup_parent_arg arg;
294*9f988b79SJean-Baptiste Boric 		/* Search parent dir */
295*9f988b79SJean-Baptiste Boric 		arg.parent_ino = 0;
296*9f988b79SJean-Baptiste Boric 		v7fs_datablock_foreach(fs, &inode, lookup_parent_from_dir_subr,
297*9f988b79SJean-Baptiste Boric 		    &arg);
298*9f988b79SJean-Baptiste Boric 		if ((parent = arg.parent_ino) == 0) {
299*9f988b79SJean-Baptiste Boric 			DPRINTF("***parent missing\n");
300*9f988b79SJean-Baptiste Boric 			return ENOENT;
301*9f988b79SJean-Baptiste Boric 		}
302*9f988b79SJean-Baptiste Boric 		/* Load parent dir */
303*9f988b79SJean-Baptiste Boric 		if ((error = v7fs_inode_load(fs, &inode, parent)))
304*9f988b79SJean-Baptiste Boric 			return error;
305*9f988b79SJean-Baptiste Boric 		if (parent == from_ino) {
306*9f988b79SJean-Baptiste Boric 			DPRINTF("#%d is child dir of #%d\n", to_ino, from_ino);
307*9f988b79SJean-Baptiste Boric 			return EINVAL;
308*9f988b79SJean-Baptiste Boric 		}
309*9f988b79SJean-Baptiste Boric 	} while (parent != V7FS_ROOT_INODE);
310*9f988b79SJean-Baptiste Boric 
311*9f988b79SJean-Baptiste Boric 	return 0;
312*9f988b79SJean-Baptiste Boric }
313*9f988b79SJean-Baptiste Boric 
314*9f988b79SJean-Baptiste Boric static int
lookup_parent_from_dir_subr(struct v7fs_self * fs,void * ctx,v7fs_daddr_t blk,size_t sz)315*9f988b79SJean-Baptiste Boric lookup_parent_from_dir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk,
316*9f988b79SJean-Baptiste Boric     size_t sz)
317*9f988b79SJean-Baptiste Boric {
318*9f988b79SJean-Baptiste Boric 	struct lookup_parent_arg *arg = (struct lookup_parent_arg *)ctx;
319*9f988b79SJean-Baptiste Boric 	char name[V7FS_NAME_MAX + 1];
320*9f988b79SJean-Baptiste Boric 	void *buf;
321*9f988b79SJean-Baptiste Boric 	int ret = 0;
322*9f988b79SJean-Baptiste Boric 
323*9f988b79SJean-Baptiste Boric 	if (!(buf = scratch_read(fs, blk)))
324*9f988b79SJean-Baptiste Boric 		return 0;
325*9f988b79SJean-Baptiste Boric 	struct v7fs_dirent *dir = (struct v7fs_dirent *)buf;
326*9f988b79SJean-Baptiste Boric 	size_t i, n = sz / sizeof(*dir);
327*9f988b79SJean-Baptiste Boric 	if (!v7fs_dirent_endian_convert(fs, dir, n)) {
328*9f988b79SJean-Baptiste Boric 		scratch_free(fs, buf);
329*9f988b79SJean-Baptiste Boric 		return V7FS_ITERATOR_ERROR;
330*9f988b79SJean-Baptiste Boric 	}
331*9f988b79SJean-Baptiste Boric 
332*9f988b79SJean-Baptiste Boric 	for (i = 0; i < n; i++, dir++) {
333*9f988b79SJean-Baptiste Boric 		v7fs_dirent_filename(name, dir->name);
334*9f988b79SJean-Baptiste Boric 		if (strncmp(dir->name, "..", V7FS_NAME_MAX) != 0)
335*9f988b79SJean-Baptiste Boric 			continue;
336*9f988b79SJean-Baptiste Boric 
337*9f988b79SJean-Baptiste Boric 		arg->parent_ino = dir->inode_number;
338*9f988b79SJean-Baptiste Boric 		ret = V7FS_ITERATOR_BREAK;
339*9f988b79SJean-Baptiste Boric 		break;
340*9f988b79SJean-Baptiste Boric 	}
341*9f988b79SJean-Baptiste Boric 
342*9f988b79SJean-Baptiste Boric 	scratch_free(fs, buf);
343*9f988b79SJean-Baptiste Boric 	return ret;
344*9f988b79SJean-Baptiste Boric }
345