1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Miscellaneous support subroutines for High Sierra filesystem 24 * 25 * Copyright (c) 1990,2000,2001 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/time.h> 34 #include <sys/cmn_err.h> 35 #include <sys/systm.h> 36 #include <sys/sysmacros.h> 37 #include <sys/buf.h> 38 #include <sys/conf.h> 39 #include <sys/user.h> 40 #include <sys/vfs.h> 41 #include <sys/vnode.h> 42 #include <sys/proc.h> 43 #include <sys/debug.h> 44 #include <sys/kmem.h> 45 #include <sys/uio.h> 46 #include <vm/hat.h> 47 #include <vm/as.h> 48 #include <vm/seg.h> 49 #include <vm/page.h> 50 #include <vm/pvn.h> 51 #include <vm/seg_map.h> 52 #include <sys/swap.h> 53 #include <vm/seg_kmem.h> 54 55 #include <sys/fs/hsfs_spec.h> 56 #include <sys/fs/hsfs_node.h> 57 #include <sys/fs/hsfs_impl.h> 58 59 #define THE_EPOCH 1970 60 #define END_OF_TIME 2099 61 62 #ifdef __STDC__ 63 static time_t hs_date_to_gmtime(int year, int mon, int day, int gmtoff); 64 #else 65 static time_t hs_date_to_gmtime(); 66 #endif 67 68 /* 69 * Table used in logging non-fatal errors which should be recorded 70 * once per mount. Indexed by HSFS_ERR values (defined in hsfs_node.h). 71 */ 72 struct hsfs_error { 73 char *hdr_text; /* msg prefix: general error type */ 74 /* must contain %s for mnt pt */ 75 char *err_text; /* specific error message */ 76 uchar_t multiple; /* > 1 such error per fs possible? */ 77 uchar_t n_printf_args; /* if err_text printf-like, # addtl args */ 78 } hsfs_error[] = { 79 /* HSFS_ERR_TRAILING_JUNK */ 80 "hsfs: Warning: the file system mounted on %s\n" 81 "does not conform to the ISO-9660 specification:", 82 " trailing blanks or null characters in file or directory name.\n", 83 1, 0, 84 /* HSFS_ERR_LOWER_CASE_NM */ 85 "hsfs: Warning: the file system mounted on %s\n" 86 "does not conform to the ISO-9660 specification: ", 87 " lower case characters in file or directory name.\n", 88 1, 0, 89 /* HSFS_ERR_BAD_ROOT_DIR */ 90 "hsfs: Warning: the file system mounted on %s\n" 91 "does not conform to the ISO-9660 specification:", 92 " invalid root directory.\n", 93 0, 0, 94 /* HSFS_ERR_UNSUP_TYPE */ 95 "hsfs: Warning: the file system mounted on %s\n" 96 "contains a file or directory with an unsupported type:", 97 " 0x%x.\n", 98 1, 1, 99 /* HSFS_ERR_BAD_FILE_LEN */ 100 "hsfs: Warning: file system mounted on %s \n" 101 "does not conform to the ISO-9660 specification:", 102 "file len greater than max allowed\n", 103 1, 0, 104 }; 105 106 107 108 /* 109 * hs_parse_dirdate 110 * 111 * Parse the short 'directory-format' date into a Unix timeval. 112 * This is the date format used in Directory Entries. 113 * 114 * If the date is not representable, make something up. 115 */ 116 void 117 hs_parse_dirdate(dp, tvp) 118 uchar_t *dp; 119 struct timeval *tvp; 120 { 121 int year, month, day, hour, minute, sec, gmtoff; 122 123 year = HDE_DATE_YEAR(dp); 124 month = HDE_DATE_MONTH(dp); 125 day = HDE_DATE_DAY(dp); 126 hour = HDE_DATE_HOUR(dp); 127 minute = HDE_DATE_MIN(dp); 128 sec = HDE_DATE_SEC(dp); 129 gmtoff = HDE_DATE_GMTOFF(dp); 130 131 tvp->tv_usec = 0; 132 if (year < THE_EPOCH) { 133 tvp->tv_sec = 0; 134 } else { 135 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 136 if (tvp->tv_sec != -1) { 137 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 138 } 139 } 140 141 return; 142 143 } 144 145 /* 146 * hs_parse_longdate 147 * 148 * Parse the long 'user-oriented' date into a Unix timeval. 149 * This is the date format used in the Volume Descriptor. 150 * 151 * If the date is not representable, make something up. 152 */ 153 void 154 hs_parse_longdate(dp, tvp) 155 uchar_t *dp; 156 struct timeval *tvp; 157 { 158 int year, month, day, hour, minute, sec, gmtoff; 159 160 year = HSV_DATE_YEAR(dp); 161 month = HSV_DATE_MONTH(dp); 162 day = HSV_DATE_DAY(dp); 163 hour = HSV_DATE_HOUR(dp); 164 minute = HSV_DATE_MIN(dp); 165 sec = HSV_DATE_SEC(dp); 166 gmtoff = HSV_DATE_GMTOFF(dp); 167 168 tvp->tv_usec = 0; 169 if (year < THE_EPOCH) { 170 tvp->tv_sec = 0; 171 } else { 172 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 173 if (tvp->tv_sec != -1) { 174 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 175 tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000; 176 } 177 } 178 179 } 180 181 /* cumulative number of seconds per month, non-leap and leap-year versions */ 182 static time_t cum_sec[] = { 183 0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280, 184 0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500 185 }; 186 static time_t cum_sec_leap[] = { 187 0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400, 188 0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680 189 }; 190 #define SEC_PER_DAY 0x15180 191 #define SEC_PER_YEAR 0x1e13380 192 193 /* 194 * hs_date_to_gmtime 195 * 196 * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1. 197 * 198 * Returns -1 if the date is out of range. 199 */ 200 static time_t 201 hs_date_to_gmtime(year, mon, day, gmtoff) 202 int year; 203 int mon; 204 int day; 205 int gmtoff; 206 { 207 time_t sum; 208 time_t *cp; 209 int y; 210 211 if ((year < THE_EPOCH) || (year > END_OF_TIME) || 212 (mon < 1) || (mon > 12) || 213 (day < 1) || (day > 31)) 214 return (-1); 215 216 /* 217 * Figure seconds until this year and correct for leap years. 218 * Note: 2000 is a leap year but not 2100. 219 */ 220 y = year - THE_EPOCH; 221 sum = y * SEC_PER_YEAR; 222 sum += ((y + 1) / 4) * SEC_PER_DAY; 223 /* 224 * Point to the correct table for this year and 225 * add in seconds until this month. 226 */ 227 cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap; 228 sum += cp[mon - 1]; 229 /* 230 * Add in seconds until 0:00 of this day. 231 * (days-per-month validation is not done here) 232 */ 233 sum += (day - 1) * SEC_PER_DAY; 234 sum -= (gmtoff * 15 * 60); 235 return (sum); 236 } 237 238 /* 239 * Indicate whether the directory is valid. 240 */ 241 242 int 243 hsfs_valid_dir(hd) 244 struct hs_direntry *hd; 245 { 246 /* 247 * check to see if this directory is not marked as a directory. 248 * check to see if data length is zero. 249 */ 250 251 if (hd->ext_size == 0) 252 return (0); 253 254 if (hd->type != VDIR) 255 return (0); 256 257 return (1); 258 } 259 260 261 262 /* 263 * If we haven't complained about this error type yet, do. 264 */ 265 void 266 hs_log_bogus_disk_warning(fsp, errtype, data) 267 struct hsfs *fsp; 268 int errtype; 269 uint_t data; 270 { 271 272 if (fsp->hsfs_err_flags & (1 << errtype)) 273 return; /* already complained */ 274 275 cmn_err(CE_NOTE, hsfs_error[errtype].hdr_text, 276 fsp->hsfs_fsmnt); 277 278 switch (hsfs_error[errtype].n_printf_args) { 279 case 0: 280 cmn_err(CE_CONT, hsfs_error[errtype].err_text); 281 break; 282 case 1: 283 cmn_err(CE_CONT, hsfs_error[errtype].err_text, data); 284 break; 285 default: 286 /* don't currently handle more than 1 arg */ 287 cmn_err(CE_CONT, "unknown problem; internal error.\n"); 288 } 289 cmn_err(CE_CONT, 290 "Due to this error, the file system may not be correctly interpreted.\n"); 291 if (hsfs_error[errtype].multiple) 292 cmn_err(CE_CONT, 293 "Other such errors in this file system will be silently ignored.\n\n"); 294 else 295 cmn_err(CE_CONT, "\n"); 296 297 fsp->hsfs_err_flags |= (1 << errtype); 298 } 299