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