1 /* $NetBSD: cd9660_node.c,v 1.33 2014/06/16 09:55:49 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.33 2014/06/16 09:55:49 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/malloc.h> 52 #include <sys/pool.h> 53 #include <sys/stat.h> 54 55 #include <fs/cd9660/iso.h> 56 #include <fs/cd9660/cd9660_extern.h> 57 #include <fs/cd9660/cd9660_node.h> 58 #include <fs/cd9660/cd9660_mount.h> 59 #include <fs/cd9660/iso_rrip.h> 60 61 extern int prtactive; /* 1 => print out reclaim of active vnodes */ 62 63 struct pool cd9660_node_pool; 64 65 static u_int cd9660_chars2ui(const u_char *, int); 66 67 /* 68 * Initialize pool for nodes. 69 */ 70 void 71 cd9660_init(void) 72 { 73 74 malloc_type_attach(M_ISOFSMNT); 75 pool_init(&cd9660_node_pool, sizeof(struct iso_node), 0, 0, 0, 76 "cd9660nopl", &pool_allocator_nointr, IPL_NONE); 77 } 78 79 /* 80 * Reinitialize. 81 */ 82 83 void 84 cd9660_reinit(void) 85 { 86 87 } 88 89 /* 90 * Destroy node pool. 91 */ 92 void 93 cd9660_done(void) 94 { 95 pool_destroy(&cd9660_node_pool); 96 malloc_type_detach(M_ISOFSMNT); 97 } 98 99 /* 100 * Last reference to an inode, write the inode out and if necessary, 101 * truncate and deallocate the file. 102 */ 103 int 104 cd9660_inactive(void *v) 105 { 106 struct vop_inactive_args /* { 107 struct vnode *a_vp; 108 bool *a_recycle; 109 } */ *ap = v; 110 struct vnode *vp = ap->a_vp; 111 struct iso_node *ip = VTOI(vp); 112 int error = 0; 113 114 /* 115 * If we are done with the inode, reclaim it 116 * so that it can be reused immediately. 117 */ 118 ip->i_flag = 0; 119 *ap->a_recycle = (ip->inode.iso_mode == 0); 120 VOP_UNLOCK(vp); 121 return error; 122 } 123 124 /* 125 * Reclaim an inode so that it can be used for other purposes. 126 */ 127 int 128 cd9660_reclaim(void *v) 129 { 130 struct vop_reclaim_args /* { 131 struct vnode *a_vp; 132 struct lwp *a_l; 133 } */ *ap = v; 134 struct vnode *vp = ap->a_vp; 135 struct iso_node *ip = VTOI(vp); 136 137 if (prtactive && vp->v_usecount > 1) 138 vprint("cd9660_reclaim: pushing active", vp); 139 /* 140 * Remove the inode from the vnode cache. 141 */ 142 vcache_remove(vp->v_mount, &ip->i_number, sizeof(ip->i_number)); 143 /* 144 * Purge old data structures associated with the inode. 145 */ 146 genfs_node_destroy(vp); 147 pool_put(&cd9660_node_pool, vp->v_data); 148 vp->v_data = NULL; 149 return (0); 150 } 151 152 /* 153 * File attributes 154 */ 155 void 156 cd9660_defattr(struct iso_directory_record *isodir, struct iso_node *inop, 157 struct buf *bp) 158 { 159 struct buf *bp2 = NULL; 160 struct iso_mnt *imp; 161 struct iso_extended_attributes *ap = NULL; 162 int off; 163 164 if (isonum_711(isodir->flags)&2) { 165 inop->inode.iso_mode = S_IFDIR; 166 /* 167 * If we return 2, fts() will assume there are no subdirectories 168 * (just links for the path and .), so instead we return 1. 169 */ 170 inop->inode.iso_links = 1; 171 } else { 172 inop->inode.iso_mode = S_IFREG; 173 inop->inode.iso_links = 1; 174 } 175 if (!bp 176 && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 177 && (off = isonum_711(isodir->ext_attr_length))) { 178 cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), 179 NULL, &bp2); 180 bp = bp2; 181 } 182 if (bp) { 183 ap = (struct iso_extended_attributes *)bp->b_data; 184 185 if (isonum_711(ap->version) == 1) { 186 if (!(ap->perm[1]&0x10)) 187 inop->inode.iso_mode |= S_IRUSR; 188 if (!(ap->perm[1]&0x40)) 189 inop->inode.iso_mode |= S_IXUSR; 190 if (!(ap->perm[0]&0x01)) 191 inop->inode.iso_mode |= S_IRGRP; 192 if (!(ap->perm[0]&0x04)) 193 inop->inode.iso_mode |= S_IXGRP; 194 if (!(ap->perm[0]&0x10)) 195 inop->inode.iso_mode |= S_IROTH; 196 if (!(ap->perm[0]&0x40)) 197 inop->inode.iso_mode |= S_IXOTH; 198 inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */ 199 inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */ 200 } else 201 ap = NULL; 202 } 203 if (!ap) { 204 inop->inode.iso_mode |= 205 S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 206 inop->inode.iso_uid = (uid_t)0; 207 inop->inode.iso_gid = (gid_t)0; 208 } 209 if (bp2) 210 brelse(bp2, 0); 211 } 212 213 /* 214 * Time stamps 215 */ 216 void 217 cd9660_deftstamp(struct iso_directory_record *isodir, struct iso_node *inop, 218 struct buf *bp) 219 { 220 struct buf *bp2 = NULL; 221 struct iso_mnt *imp; 222 struct iso_extended_attributes *ap = NULL; 223 int off; 224 225 if (!bp 226 && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 227 && (off = isonum_711(isodir->ext_attr_length))) { 228 cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), 229 NULL, &bp2); 230 bp = bp2; 231 } 232 if (bp) { 233 ap = (struct iso_extended_attributes *)bp->b_data; 234 235 if (isonum_711(ap->version) == 1) { 236 if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime)) 237 cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime); 238 if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime)) 239 inop->inode.iso_ctime = inop->inode.iso_atime; 240 if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime)) 241 inop->inode.iso_mtime = inop->inode.iso_ctime; 242 } else 243 ap = NULL; 244 } 245 if (!ap) { 246 cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime); 247 inop->inode.iso_atime = inop->inode.iso_ctime; 248 inop->inode.iso_mtime = inop->inode.iso_ctime; 249 } 250 if (bp2) 251 brelse(bp2, 0); 252 } 253 254 int 255 cd9660_tstamp_conv7(const u_char *pi, struct timespec *pu) 256 { 257 int crtime, days; 258 int y, m, d, hour, minute, second, tz; 259 260 y = pi[0] + 1900; 261 m = pi[1]; 262 d = pi[2]; 263 hour = pi[3]; 264 minute = pi[4]; 265 second = pi[5]; 266 tz = pi[6]; 267 268 if (y < 1970) { 269 pu->tv_sec = 0; 270 pu->tv_nsec = 0; 271 return 0; 272 } else { 273 #ifdef ORIGINAL 274 /* computes day number relative to Sept. 19th,1989 */ 275 /* don't even *THINK* about changing formula. It works! */ 276 days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100; 277 #else 278 /* 279 * Changed :-) to make it relative to Jan. 1st, 1970 280 * and to disambiguate negative division 281 */ 282 days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239; 283 #endif 284 crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second; 285 286 /* timezone offset is unreliable on some disks */ 287 if (-48 <= tz && tz <= 52) 288 crtime -= tz * 15 * 60; 289 } 290 pu->tv_sec = crtime; 291 pu->tv_nsec = 0; 292 return 1; 293 } 294 295 static u_int 296 cd9660_chars2ui(const u_char *begin, int len) 297 { 298 u_int rc; 299 300 for (rc = 0; --len >= 0;) { 301 rc *= 10; 302 rc += *begin++ - '0'; 303 } 304 return rc; 305 } 306 307 int 308 cd9660_tstamp_conv17(const u_char *pi, struct timespec *pu) 309 { 310 u_char tbuf[7]; 311 312 /* year:"0001"-"9999" -> -1900 */ 313 tbuf[0] = cd9660_chars2ui(pi,4) - 1900; 314 315 /* month: " 1"-"12" -> 1 - 12 */ 316 tbuf[1] = cd9660_chars2ui(pi + 4,2); 317 318 /* day: " 1"-"31" -> 1 - 31 */ 319 tbuf[2] = cd9660_chars2ui(pi + 6,2); 320 321 /* hour: " 0"-"23" -> 0 - 23 */ 322 tbuf[3] = cd9660_chars2ui(pi + 8,2); 323 324 /* minute:" 0"-"59" -> 0 - 59 */ 325 tbuf[4] = cd9660_chars2ui(pi + 10,2); 326 327 /* second:" 0"-"59" -> 0 - 59 */ 328 tbuf[5] = cd9660_chars2ui(pi + 12,2); 329 330 /* difference of GMT */ 331 tbuf[6] = pi[16]; 332 333 return cd9660_tstamp_conv7(tbuf,pu); 334 } 335 336 ino_t 337 isodirino(struct iso_directory_record *isodir, struct iso_mnt *imp) 338 { 339 ino_t ino; 340 341 /* 342 * Note there is an inverse calculation in 343 * cd9660_vfsops.c:cd9660_loadvnode(): 344 * ip->iso_start = ino >> imp->im_bshift; 345 * and also a calculation of the isodir pointer 346 * from an inode in cd9660_vnops.c:cd9660_readlink() 347 */ 348 ino = ((ino_t)isonum_733(isodir->extent) + 349 isonum_711(isodir->ext_attr_length)) << imp->im_bshift; 350 return ino; 351 } 352