1 | /* $NetBSD: cd9660_node.c,v 1.35 2016/08/20 12:37:06 hannken Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1982, 1986, 1989, 1994 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to Berkeley |
8 | * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension |
9 | * Support code is derived from software contributed to Berkeley |
10 | * by Atsushi Murai (amurai@spec.co.jp). |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * 3. Neither the name of the University nor the names of its contributors |
21 | * may be used to endorse or promote products derived from this software |
22 | * without specific prior written permission. |
23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. |
35 | * |
36 | * @(#)cd9660_node.c 8.8 (Berkeley) 5/22/95 |
37 | */ |
38 | |
39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: cd9660_node.c,v 1.35 2016/08/20 12:37:06 hannken Exp $" ); |
41 | |
42 | #include <sys/param.h> |
43 | #include <sys/systm.h> |
44 | #include <sys/mount.h> |
45 | #include <sys/proc.h> |
46 | #include <sys/file.h> |
47 | #include <sys/buf.h> |
48 | #include <sys/vnode.h> |
49 | #include <sys/namei.h> |
50 | #include <sys/kernel.h> |
51 | #include <sys/pool.h> |
52 | #include <sys/stat.h> |
53 | |
54 | #include <fs/cd9660/iso.h> |
55 | #include <fs/cd9660/cd9660_extern.h> |
56 | #include <fs/cd9660/cd9660_node.h> |
57 | #include <fs/cd9660/cd9660_mount.h> |
58 | #include <fs/cd9660/iso_rrip.h> |
59 | |
60 | extern int prtactive; /* 1 => print out reclaim of active vnodes */ |
61 | |
62 | struct pool cd9660_node_pool; |
63 | |
64 | static u_int cd9660_chars2ui(const u_char *, int); |
65 | |
66 | /* |
67 | * Initialize pool for nodes. |
68 | */ |
69 | void |
70 | cd9660_init(void) |
71 | { |
72 | |
73 | malloc_type_attach(M_ISOFSMNT); |
74 | pool_init(&cd9660_node_pool, sizeof(struct iso_node), 0, 0, 0, |
75 | "cd9660nopl" , &pool_allocator_nointr, IPL_NONE); |
76 | } |
77 | |
78 | /* |
79 | * Reinitialize. |
80 | */ |
81 | |
82 | void |
83 | cd9660_reinit(void) |
84 | { |
85 | |
86 | } |
87 | |
88 | /* |
89 | * Destroy node pool. |
90 | */ |
91 | void |
92 | cd9660_done(void) |
93 | { |
94 | pool_destroy(&cd9660_node_pool); |
95 | malloc_type_detach(M_ISOFSMNT); |
96 | } |
97 | |
98 | /* |
99 | * Last reference to an inode, write the inode out and if necessary, |
100 | * truncate and deallocate the file. |
101 | */ |
102 | int |
103 | cd9660_inactive(void *v) |
104 | { |
105 | struct vop_inactive_args /* { |
106 | struct vnode *a_vp; |
107 | bool *a_recycle; |
108 | } */ *ap = v; |
109 | struct vnode *vp = ap->a_vp; |
110 | struct iso_node *ip = VTOI(vp); |
111 | int error = 0; |
112 | |
113 | /* |
114 | * If we are done with the inode, reclaim it |
115 | * so that it can be reused immediately. |
116 | */ |
117 | ip->i_flag = 0; |
118 | *ap->a_recycle = (ip->inode.iso_mode == 0); |
119 | VOP_UNLOCK(vp); |
120 | return error; |
121 | } |
122 | |
123 | /* |
124 | * Reclaim an inode so that it can be used for other purposes. |
125 | */ |
126 | int |
127 | cd9660_reclaim(void *v) |
128 | { |
129 | struct vop_reclaim_args /* { |
130 | struct vnode *a_vp; |
131 | struct lwp *a_l; |
132 | } */ *ap = v; |
133 | struct vnode *vp = ap->a_vp; |
134 | |
135 | if (prtactive && vp->v_usecount > 1) |
136 | vprint("cd9660_reclaim: pushing active" , vp); |
137 | /* |
138 | * Purge old data structures associated with the inode. |
139 | */ |
140 | genfs_node_destroy(vp); |
141 | pool_put(&cd9660_node_pool, vp->v_data); |
142 | vp->v_data = NULL; |
143 | return (0); |
144 | } |
145 | |
146 | /* |
147 | * File attributes |
148 | */ |
149 | void |
150 | cd9660_defattr(struct iso_directory_record *isodir, struct iso_node *inop, |
151 | struct buf *bp) |
152 | { |
153 | struct buf *bp2 = NULL; |
154 | struct iso_mnt *imp; |
155 | struct iso_extended_attributes *ap = NULL; |
156 | int off; |
157 | |
158 | if (isonum_711(isodir->flags)&2) { |
159 | inop->inode.iso_mode = S_IFDIR; |
160 | /* |
161 | * If we return 2, fts() will assume there are no subdirectories |
162 | * (just links for the path and .), so instead we return 1. |
163 | */ |
164 | inop->inode.iso_links = 1; |
165 | } else { |
166 | inop->inode.iso_mode = S_IFREG; |
167 | inop->inode.iso_links = 1; |
168 | } |
169 | if (!bp |
170 | && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) |
171 | && (off = isonum_711(isodir->ext_attr_length))) { |
172 | cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), |
173 | NULL, &bp2); |
174 | bp = bp2; |
175 | } |
176 | if (bp) { |
177 | ap = (struct iso_extended_attributes *)bp->b_data; |
178 | |
179 | if (isonum_711(ap->version) == 1) { |
180 | if (!(ap->perm[1]&0x10)) |
181 | inop->inode.iso_mode |= S_IRUSR; |
182 | if (!(ap->perm[1]&0x40)) |
183 | inop->inode.iso_mode |= S_IXUSR; |
184 | if (!(ap->perm[0]&0x01)) |
185 | inop->inode.iso_mode |= S_IRGRP; |
186 | if (!(ap->perm[0]&0x04)) |
187 | inop->inode.iso_mode |= S_IXGRP; |
188 | if (!(ap->perm[0]&0x10)) |
189 | inop->inode.iso_mode |= S_IROTH; |
190 | if (!(ap->perm[0]&0x40)) |
191 | inop->inode.iso_mode |= S_IXOTH; |
192 | inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */ |
193 | inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */ |
194 | } else |
195 | ap = NULL; |
196 | } |
197 | if (!ap) { |
198 | inop->inode.iso_mode |= |
199 | S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; |
200 | inop->inode.iso_uid = (uid_t)0; |
201 | inop->inode.iso_gid = (gid_t)0; |
202 | } |
203 | if (bp2) |
204 | brelse(bp2, 0); |
205 | } |
206 | |
207 | /* |
208 | * Time stamps |
209 | */ |
210 | void |
211 | cd9660_deftstamp(struct iso_directory_record *isodir, struct iso_node *inop, |
212 | struct buf *bp) |
213 | { |
214 | struct buf *bp2 = NULL; |
215 | struct iso_mnt *imp; |
216 | struct iso_extended_attributes *ap = NULL; |
217 | int off; |
218 | |
219 | if (!bp |
220 | && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) |
221 | && (off = isonum_711(isodir->ext_attr_length))) { |
222 | cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), |
223 | NULL, &bp2); |
224 | bp = bp2; |
225 | } |
226 | if (bp) { |
227 | ap = (struct iso_extended_attributes *)bp->b_data; |
228 | |
229 | if (isonum_711(ap->version) == 1) { |
230 | if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime)) |
231 | cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime); |
232 | if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime)) |
233 | inop->inode.iso_ctime = inop->inode.iso_atime; |
234 | if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime)) |
235 | inop->inode.iso_mtime = inop->inode.iso_ctime; |
236 | } else |
237 | ap = NULL; |
238 | } |
239 | if (!ap) { |
240 | cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime); |
241 | inop->inode.iso_atime = inop->inode.iso_ctime; |
242 | inop->inode.iso_mtime = inop->inode.iso_ctime; |
243 | } |
244 | if (bp2) |
245 | brelse(bp2, 0); |
246 | } |
247 | |
248 | int |
249 | cd9660_tstamp_conv7(const u_char *pi, struct timespec *pu) |
250 | { |
251 | int crtime, days; |
252 | int y, m, d, hour, minute, second, tz; |
253 | |
254 | y = pi[0] + 1900; |
255 | m = pi[1]; |
256 | d = pi[2]; |
257 | hour = pi[3]; |
258 | minute = pi[4]; |
259 | second = pi[5]; |
260 | tz = pi[6]; |
261 | |
262 | if (y < 1970) { |
263 | pu->tv_sec = 0; |
264 | pu->tv_nsec = 0; |
265 | return 0; |
266 | } else { |
267 | #ifdef ORIGINAL |
268 | /* computes day number relative to Sept. 19th,1989 */ |
269 | /* don't even *THINK* about changing formula. It works! */ |
270 | days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100; |
271 | #else |
272 | /* |
273 | * Changed :-) to make it relative to Jan. 1st, 1970 |
274 | * and to disambiguate negative division |
275 | */ |
276 | days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239; |
277 | #endif |
278 | crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second; |
279 | |
280 | /* timezone offset is unreliable on some disks */ |
281 | if (-48 <= tz && tz <= 52) |
282 | crtime -= tz * 15 * 60; |
283 | } |
284 | pu->tv_sec = crtime; |
285 | pu->tv_nsec = 0; |
286 | return 1; |
287 | } |
288 | |
289 | static u_int |
290 | cd9660_chars2ui(const u_char *begin, int len) |
291 | { |
292 | u_int rc; |
293 | |
294 | for (rc = 0; --len >= 0;) { |
295 | rc *= 10; |
296 | rc += *begin++ - '0'; |
297 | } |
298 | return rc; |
299 | } |
300 | |
301 | int |
302 | cd9660_tstamp_conv17(const u_char *pi, struct timespec *pu) |
303 | { |
304 | u_char tbuf[7]; |
305 | |
306 | /* year:"0001"-"9999" -> -1900 */ |
307 | tbuf[0] = cd9660_chars2ui(pi,4) - 1900; |
308 | |
309 | /* month: " 1"-"12" -> 1 - 12 */ |
310 | tbuf[1] = cd9660_chars2ui(pi + 4,2); |
311 | |
312 | /* day: " 1"-"31" -> 1 - 31 */ |
313 | tbuf[2] = cd9660_chars2ui(pi + 6,2); |
314 | |
315 | /* hour: " 0"-"23" -> 0 - 23 */ |
316 | tbuf[3] = cd9660_chars2ui(pi + 8,2); |
317 | |
318 | /* minute:" 0"-"59" -> 0 - 59 */ |
319 | tbuf[4] = cd9660_chars2ui(pi + 10,2); |
320 | |
321 | /* second:" 0"-"59" -> 0 - 59 */ |
322 | tbuf[5] = cd9660_chars2ui(pi + 12,2); |
323 | |
324 | /* difference of GMT */ |
325 | tbuf[6] = pi[16]; |
326 | |
327 | return cd9660_tstamp_conv7(tbuf,pu); |
328 | } |
329 | |
330 | ino_t |
331 | isodirino(struct iso_directory_record *isodir, struct iso_mnt *imp) |
332 | { |
333 | ino_t ino; |
334 | |
335 | /* |
336 | * Note there is an inverse calculation in |
337 | * cd9660_vfsops.c:cd9660_loadvnode(): |
338 | * ip->iso_start = ino >> imp->im_bshift; |
339 | * and also a calculation of the isodir pointer |
340 | * from an inode in cd9660_vnops.c:cd9660_readlink() |
341 | */ |
342 | ino = ((ino_t)isonum_733(isodir->extent) + |
343 | isonum_711(isodir->ext_attr_length)) << imp->im_bshift; |
344 | return ino; |
345 | } |
346 | |