1df8bae1dSRodney W. Grimes /*- 2*51369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*51369649SPedro F. Giffuni * 4996c772fSJohn Dyson * Copyright (c) 1982, 1986, 1989, 1994, 1995 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley 8df8bae1dSRodney W. Grimes * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 9df8bae1dSRodney W. Grimes * Support code is derived from software contributed to Berkeley 10df8bae1dSRodney W. Grimes * by Atsushi Murai (amurai@spec.co.jp). 11df8bae1dSRodney W. Grimes * 12df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 13df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 14df8bae1dSRodney W. Grimes * are met: 15df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 17df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 19df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 20fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 36df8bae1dSRodney W. Grimes * @(#)cd9660_node.c 8.2 (Berkeley) 1/23/94 37df8bae1dSRodney W. Grimes */ 38df8bae1dSRodney W. Grimes 398c9bbf48SDavid E. O'Brien #include <sys/cdefs.h> 408c9bbf48SDavid E. O'Brien __FBSDID("$FreeBSD$"); 418c9bbf48SDavid E. O'Brien 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 44df8bae1dSRodney W. Grimes #include <sys/mount.h> 459626b608SPoul-Henning Kamp #include <sys/bio.h> 46df8bae1dSRodney W. Grimes #include <sys/buf.h> 47df8bae1dSRodney W. Grimes #include <sys/vnode.h> 48df8bae1dSRodney W. Grimes #include <sys/malloc.h> 49df8bae1dSRodney W. Grimes #include <sys/stat.h> 501b367556SJason Evans #include <sys/mutex.h> 51a18b1f1dSJason Evans 52a8d36d0dSCraig Rodrigues #include <fs/cd9660/iso.h> 53a8d36d0dSCraig Rodrigues #include <fs/cd9660/cd9660_node.h> 54a8d36d0dSCraig Rodrigues #include <fs/cd9660/cd9660_mount.h> 55df8bae1dSRodney W. Grimes 5689c9a483SAlfred Perlstein static unsigned cd9660_chars2ui(unsigned char *begin, int len); 5710dd32cdSBruce Evans 58df8bae1dSRodney W. Grimes /* 59df8bae1dSRodney W. Grimes * Last reference to an inode, write the inode out and if necessary, 60df8bae1dSRodney W. Grimes * truncate and deallocate the file. 61df8bae1dSRodney W. Grimes */ 62df8bae1dSRodney W. Grimes int 63df8bae1dSRodney W. Grimes cd9660_inactive(ap) 64df8bae1dSRodney W. Grimes struct vop_inactive_args /* { 65df8bae1dSRodney W. Grimes struct vnode *a_vp; 66b40ce416SJulian Elischer struct thread *a_td; 67df8bae1dSRodney W. Grimes } */ *ap; 68df8bae1dSRodney W. Grimes { 69df8bae1dSRodney W. Grimes struct vnode *vp = ap->a_vp; 70bffd1b7aSPoul-Henning Kamp struct iso_node *ip = VTOI(vp); 711295d82eSGary Palmer int error = 0; 72df8bae1dSRodney W. Grimes 73df8bae1dSRodney W. Grimes /* 74df8bae1dSRodney W. Grimes * If we are done with the inode, reclaim it 75df8bae1dSRodney W. Grimes * so that it can be reused immediately. 76df8bae1dSRodney W. Grimes */ 77996c772fSJohn Dyson if (ip->inode.iso_mode == 0) 78af6e6b87SEdward Tomasz Napierala vrecycle(vp); 79df8bae1dSRodney W. Grimes return error; 80df8bae1dSRodney W. Grimes } 81df8bae1dSRodney W. Grimes 82df8bae1dSRodney W. Grimes /* 83df8bae1dSRodney W. Grimes * Reclaim an inode so that it can be used for other purposes. 84df8bae1dSRodney W. Grimes */ 85df8bae1dSRodney W. Grimes int 86df8bae1dSRodney W. Grimes cd9660_reclaim(ap) 87df8bae1dSRodney W. Grimes struct vop_reclaim_args /* { 88df8bae1dSRodney W. Grimes struct vnode *a_vp; 89b40ce416SJulian Elischer struct thread *a_td; 90df8bae1dSRodney W. Grimes } */ *ap; 91df8bae1dSRodney W. Grimes { 92bffd1b7aSPoul-Henning Kamp struct vnode *vp = ap->a_vp; 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes /* 9592e73f57SAlfred Perlstein * Destroy the vm object and flush associated pages. 9692e73f57SAlfred Perlstein */ 9792e73f57SAlfred Perlstein vnode_destroy_vobject(vp); 9892e73f57SAlfred Perlstein /* 99df8bae1dSRodney W. Grimes * Remove the inode from its hash chain. 100df8bae1dSRodney W. Grimes */ 101dfb9f846SPoul-Henning Kamp vfs_hash_remove(vp); 102dfb9f846SPoul-Henning Kamp 103df8bae1dSRodney W. Grimes /* 104df8bae1dSRodney W. Grimes * Purge old data structures associated with the inode. 105df8bae1dSRodney W. Grimes */ 1061ede983cSDag-Erling Smørgrav free(vp->v_data, M_ISOFSNODE); 107df8bae1dSRodney W. Grimes vp->v_data = NULL; 10826f9a767SRodney W. Grimes return (0); 109df8bae1dSRodney W. Grimes } 110df8bae1dSRodney W. Grimes 111df8bae1dSRodney W. Grimes /* 112df8bae1dSRodney W. Grimes * File attributes 113df8bae1dSRodney W. Grimes */ 114df8bae1dSRodney W. Grimes void 115988fa8efSJoerg Wunsch cd9660_defattr(isodir, inop, bp, ftype) 116df8bae1dSRodney W. Grimes struct iso_directory_record *isodir; 117df8bae1dSRodney W. Grimes struct iso_node *inop; 118df8bae1dSRodney W. Grimes struct buf *bp; 119988fa8efSJoerg Wunsch enum ISO_FTYPE ftype; 120df8bae1dSRodney W. Grimes { 121df8bae1dSRodney W. Grimes struct buf *bp2 = NULL; 122df8bae1dSRodney W. Grimes struct iso_mnt *imp; 123df8bae1dSRodney W. Grimes struct iso_extended_attributes *ap = NULL; 124df8bae1dSRodney W. Grimes int off; 125df8bae1dSRodney W. Grimes 126988fa8efSJoerg Wunsch /* high sierra does not have timezone data, flag is one byte ahead */ 127988fa8efSJoerg Wunsch if (isonum_711(ftype == ISO_FTYPE_HIGH_SIERRA? 128988fa8efSJoerg Wunsch &isodir->date[6]: isodir->flags)&2) { 129df8bae1dSRodney W. Grimes inop->inode.iso_mode = S_IFDIR; 130df8bae1dSRodney W. Grimes /* 131df8bae1dSRodney W. Grimes * If we return 2, fts() will assume there are no subdirectories 132df8bae1dSRodney W. Grimes * (just links for the path and .), so instead we return 1. 133df8bae1dSRodney W. Grimes */ 134df8bae1dSRodney W. Grimes inop->inode.iso_links = 1; 135df8bae1dSRodney W. Grimes } else { 136df8bae1dSRodney W. Grimes inop->inode.iso_mode = S_IFREG; 137df8bae1dSRodney W. Grimes inop->inode.iso_links = 1; 138df8bae1dSRodney W. Grimes } 139df8bae1dSRodney W. Grimes if (!bp 140df8bae1dSRodney W. Grimes && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 141df8bae1dSRodney W. Grimes && (off = isonum_711(isodir->ext_attr_length))) { 142cec0f20cSPoul-Henning Kamp cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, 143996c772fSJohn Dyson &bp2); 144df8bae1dSRodney W. Grimes bp = bp2; 145df8bae1dSRodney W. Grimes } 146df8bae1dSRodney W. Grimes if (bp) { 147996c772fSJohn Dyson ap = (struct iso_extended_attributes *)bp->b_data; 148df8bae1dSRodney W. Grimes 149df8bae1dSRodney W. Grimes if (isonum_711(ap->version) == 1) { 150df8bae1dSRodney W. Grimes if (!(ap->perm[0]&0x40)) 151464119c4SEdward Tomasz Napierala inop->inode.iso_mode |= S_IXOTH; 152df8bae1dSRodney W. Grimes if (!(ap->perm[0]&0x10)) 153464119c4SEdward Tomasz Napierala inop->inode.iso_mode |= S_IROTH; 154df8bae1dSRodney W. Grimes if (!(ap->perm[0]&4)) 155464119c4SEdward Tomasz Napierala inop->inode.iso_mode |= S_IXGRP; 156df8bae1dSRodney W. Grimes if (!(ap->perm[0]&1)) 157464119c4SEdward Tomasz Napierala inop->inode.iso_mode |= S_IRGRP; 158df8bae1dSRodney W. Grimes if (!(ap->perm[1]&0x40)) 159464119c4SEdward Tomasz Napierala inop->inode.iso_mode |= S_IXUSR; 160df8bae1dSRodney W. Grimes if (!(ap->perm[1]&0x10)) 161464119c4SEdward Tomasz Napierala inop->inode.iso_mode |= S_IRUSR; 162df8bae1dSRodney W. Grimes inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */ 163df8bae1dSRodney W. Grimes inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */ 164df8bae1dSRodney W. Grimes } else 165df8bae1dSRodney W. Grimes ap = NULL; 166df8bae1dSRodney W. Grimes } 167df8bae1dSRodney W. Grimes if (!ap) { 168464119c4SEdward Tomasz Napierala inop->inode.iso_mode |= S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 169df8bae1dSRodney W. Grimes inop->inode.iso_uid = (uid_t)0; 170df8bae1dSRodney W. Grimes inop->inode.iso_gid = (gid_t)0; 171df8bae1dSRodney W. Grimes } 172df8bae1dSRodney W. Grimes if (bp2) 173df8bae1dSRodney W. Grimes brelse(bp2); 174df8bae1dSRodney W. Grimes } 175df8bae1dSRodney W. Grimes 176df8bae1dSRodney W. Grimes /* 177df8bae1dSRodney W. Grimes * Time stamps 178df8bae1dSRodney W. Grimes */ 179df8bae1dSRodney W. Grimes void 180988fa8efSJoerg Wunsch cd9660_deftstamp(isodir,inop,bp,ftype) 181df8bae1dSRodney W. Grimes struct iso_directory_record *isodir; 182df8bae1dSRodney W. Grimes struct iso_node *inop; 183df8bae1dSRodney W. Grimes struct buf *bp; 184988fa8efSJoerg Wunsch enum ISO_FTYPE ftype; 185df8bae1dSRodney W. Grimes { 186df8bae1dSRodney W. Grimes struct buf *bp2 = NULL; 187df8bae1dSRodney W. Grimes struct iso_mnt *imp; 188df8bae1dSRodney W. Grimes struct iso_extended_attributes *ap = NULL; 189df8bae1dSRodney W. Grimes int off; 190df8bae1dSRodney W. Grimes 191df8bae1dSRodney W. Grimes if (!bp 192df8bae1dSRodney W. Grimes && ((imp = inop->i_mnt)->im_flags & ISOFSMNT_EXTATT) 193df8bae1dSRodney W. Grimes && (off = isonum_711(isodir->ext_attr_length))) { 194cec0f20cSPoul-Henning Kamp cd9660_blkatoff(ITOV(inop), (off_t)-(off << imp->im_bshift), NULL, 195996c772fSJohn Dyson &bp2); 196df8bae1dSRodney W. Grimes bp = bp2; 197df8bae1dSRodney W. Grimes } 198df8bae1dSRodney W. Grimes if (bp) { 199996c772fSJohn Dyson ap = (struct iso_extended_attributes *)bp->b_data; 200df8bae1dSRodney W. Grimes 201596d40b9SBruce Evans if (ftype != ISO_FTYPE_HIGH_SIERRA 202596d40b9SBruce Evans && isonum_711(ap->version) == 1) { 203df8bae1dSRodney W. Grimes if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime)) 204df8bae1dSRodney W. Grimes cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime); 205df8bae1dSRodney W. Grimes if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime)) 206df8bae1dSRodney W. Grimes inop->inode.iso_ctime = inop->inode.iso_atime; 207df8bae1dSRodney W. Grimes if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime)) 208df8bae1dSRodney W. Grimes inop->inode.iso_mtime = inop->inode.iso_ctime; 209df8bae1dSRodney W. Grimes } else 210df8bae1dSRodney W. Grimes ap = NULL; 211df8bae1dSRodney W. Grimes } 212df8bae1dSRodney W. Grimes if (!ap) { 213988fa8efSJoerg Wunsch cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime,ftype); 214df8bae1dSRodney W. Grimes inop->inode.iso_atime = inop->inode.iso_ctime; 215df8bae1dSRodney W. Grimes inop->inode.iso_mtime = inop->inode.iso_ctime; 216df8bae1dSRodney W. Grimes } 217df8bae1dSRodney W. Grimes if (bp2) 218df8bae1dSRodney W. Grimes brelse(bp2); 219df8bae1dSRodney W. Grimes } 220df8bae1dSRodney W. Grimes 221df8bae1dSRodney W. Grimes int 222988fa8efSJoerg Wunsch cd9660_tstamp_conv7(pi,pu,ftype) 223996c772fSJohn Dyson u_char *pi; 2241dbaf90cSBruce Evans struct timespec *pu; 225988fa8efSJoerg Wunsch enum ISO_FTYPE ftype; 226df8bae1dSRodney W. Grimes { 227df8bae1dSRodney W. Grimes int crtime, days; 228df8bae1dSRodney W. Grimes int y, m, d, hour, minute, second, tz; 229df8bae1dSRodney W. Grimes 230df8bae1dSRodney W. Grimes y = pi[0] + 1900; 231df8bae1dSRodney W. Grimes m = pi[1]; 232df8bae1dSRodney W. Grimes d = pi[2]; 233df8bae1dSRodney W. Grimes hour = pi[3]; 234df8bae1dSRodney W. Grimes minute = pi[4]; 235df8bae1dSRodney W. Grimes second = pi[5]; 236988fa8efSJoerg Wunsch if(ftype != ISO_FTYPE_HIGH_SIERRA) 2375c423e06STim Kientzle tz = ((signed char *)pi)[6]; /* Timezone value is signed. */ 238988fa8efSJoerg Wunsch else 239988fa8efSJoerg Wunsch /* original high sierra misses timezone data */ 240988fa8efSJoerg Wunsch tz = 0; 241df8bae1dSRodney W. Grimes 242df8bae1dSRodney W. Grimes if (y < 1970) { 24395a1574eSNate Williams pu->tv_sec = 0; 24495a1574eSNate Williams pu->tv_nsec = 0; 245df8bae1dSRodney W. Grimes return 0; 246df8bae1dSRodney W. Grimes } else { 247df8bae1dSRodney W. Grimes #ifdef ORIGINAL 248df8bae1dSRodney W. Grimes /* computes day number relative to Sept. 19th,1989 */ 249df8bae1dSRodney W. Grimes /* don't even *THINK* about changing formula. It works! */ 250df8bae1dSRodney W. Grimes days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100; 251df8bae1dSRodney W. Grimes #else 252df8bae1dSRodney W. Grimes /* 253df8bae1dSRodney W. Grimes * Changed :-) to make it relative to Jan. 1st, 1970 254df8bae1dSRodney W. Grimes * and to disambiguate negative division 255df8bae1dSRodney W. Grimes */ 256df8bae1dSRodney W. Grimes days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239; 257df8bae1dSRodney W. Grimes #endif 258df8bae1dSRodney W. Grimes crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second; 259df8bae1dSRodney W. Grimes 260df8bae1dSRodney W. Grimes /* timezone offset is unreliable on some disks */ 261df8bae1dSRodney W. Grimes if (-48 <= tz && tz <= 52) 2622d091ecfSBruce Evans crtime -= tz * 15 * 60; 263df8bae1dSRodney W. Grimes } 26495a1574eSNate Williams pu->tv_sec = crtime; 26595a1574eSNate Williams pu->tv_nsec = 0; 266df8bae1dSRodney W. Grimes return 1; 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes 269996c772fSJohn Dyson static u_int 270df8bae1dSRodney W. Grimes cd9660_chars2ui(begin,len) 271996c772fSJohn Dyson u_char *begin; 272df8bae1dSRodney W. Grimes int len; 273df8bae1dSRodney W. Grimes { 274996c772fSJohn Dyson u_int rc; 275df8bae1dSRodney W. Grimes 276df8bae1dSRodney W. Grimes for (rc = 0; --len >= 0;) { 277df8bae1dSRodney W. Grimes rc *= 10; 278df8bae1dSRodney W. Grimes rc += *begin++ - '0'; 279df8bae1dSRodney W. Grimes } 280df8bae1dSRodney W. Grimes return rc; 281df8bae1dSRodney W. Grimes } 282df8bae1dSRodney W. Grimes 283df8bae1dSRodney W. Grimes int 284df8bae1dSRodney W. Grimes cd9660_tstamp_conv17(pi,pu) 285996c772fSJohn Dyson u_char *pi; 2861dbaf90cSBruce Evans struct timespec *pu; 287df8bae1dSRodney W. Grimes { 288996c772fSJohn Dyson u_char buf[7]; 289df8bae1dSRodney W. Grimes 290df8bae1dSRodney W. Grimes /* year:"0001"-"9999" -> -1900 */ 291df8bae1dSRodney W. Grimes buf[0] = cd9660_chars2ui(pi,4) - 1900; 292df8bae1dSRodney W. Grimes 293df8bae1dSRodney W. Grimes /* month: " 1"-"12" -> 1 - 12 */ 294df8bae1dSRodney W. Grimes buf[1] = cd9660_chars2ui(pi + 4,2); 295df8bae1dSRodney W. Grimes 296df8bae1dSRodney W. Grimes /* day: " 1"-"31" -> 1 - 31 */ 297df8bae1dSRodney W. Grimes buf[2] = cd9660_chars2ui(pi + 6,2); 298df8bae1dSRodney W. Grimes 299df8bae1dSRodney W. Grimes /* hour: " 0"-"23" -> 0 - 23 */ 300df8bae1dSRodney W. Grimes buf[3] = cd9660_chars2ui(pi + 8,2); 301df8bae1dSRodney W. Grimes 302df8bae1dSRodney W. Grimes /* minute:" 0"-"59" -> 0 - 59 */ 303df8bae1dSRodney W. Grimes buf[4] = cd9660_chars2ui(pi + 10,2); 304df8bae1dSRodney W. Grimes 305df8bae1dSRodney W. Grimes /* second:" 0"-"59" -> 0 - 59 */ 306df8bae1dSRodney W. Grimes buf[5] = cd9660_chars2ui(pi + 12,2); 307df8bae1dSRodney W. Grimes 308df8bae1dSRodney W. Grimes /* difference of GMT */ 309df8bae1dSRodney W. Grimes buf[6] = pi[16]; 310df8bae1dSRodney W. Grimes 311988fa8efSJoerg Wunsch return cd9660_tstamp_conv7(buf, pu, ISO_FTYPE_DEFAULT); 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes 314dbaab6e6SConrad Meyer cd_ino_t 315996c772fSJohn Dyson isodirino(isodir, imp) 316df8bae1dSRodney W. Grimes struct iso_directory_record *isodir; 317df8bae1dSRodney W. Grimes struct iso_mnt *imp; 318df8bae1dSRodney W. Grimes { 319dbaab6e6SConrad Meyer cd_ino_t ino; 320996c772fSJohn Dyson 321c8227de2SConrad Meyer /* 322c8227de2SConrad Meyer * Note there is an inverse calculation in 323c8227de2SConrad Meyer * cd9660_vfsops.c:cd9660_vget_internal(): 324c8227de2SConrad Meyer * ip->iso_start = ino >> imp->im_bshift; 325c8227de2SConrad Meyer * and also a calculation of the isodir pointer 326c8227de2SConrad Meyer * from an inode in cd9660_vnops.c:cd9660_readlink() 327c8227de2SConrad Meyer */ 328c8227de2SConrad Meyer ino = ((cd_ino_t)isonum_733(isodir->extent) + 329c8227de2SConrad Meyer isonum_711(isodir->ext_attr_length)) << imp->im_bshift; 330c8227de2SConrad Meyer return ino; 331df8bae1dSRodney W. Grimes } 332