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