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 2007 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 /* HSFS_ERR_NEG_SUA_LEN */ 119 "hsfs: Warning: file system mounted on %s " 120 "has inconsistent Rock Ridge data:", 121 "negative SUA len\n", 122 1, 0, 123 /* HSFS_ERR_BAD_SUA_LEN */ 124 "hsfs: Warning: file system mounted on %s " 125 "has inconsistent Rock Ridge data:", 126 "SUA len too big\n", 127 1, 0, 128 }; 129 130 131 132 /* 133 * hs_parse_dirdate 134 * 135 * Parse the short 'directory-format' date into a Unix timeval. 136 * This is the date format used in Directory Entries. 137 * 138 * If the date is not representable, make something up. 139 */ 140 void 141 hs_parse_dirdate(dp, tvp) 142 uchar_t *dp; 143 struct timeval *tvp; 144 { 145 int year, month, day, hour, minute, sec, gmtoff; 146 147 year = HDE_DATE_YEAR(dp); 148 month = HDE_DATE_MONTH(dp); 149 day = HDE_DATE_DAY(dp); 150 hour = HDE_DATE_HOUR(dp); 151 minute = HDE_DATE_MIN(dp); 152 sec = HDE_DATE_SEC(dp); 153 gmtoff = HDE_DATE_GMTOFF(dp); 154 155 tvp->tv_usec = 0; 156 if (year < THE_EPOCH) { 157 tvp->tv_sec = 0; 158 } else { 159 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 160 if (tvp->tv_sec != -1) { 161 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 162 } 163 } 164 165 return; 166 167 } 168 169 /* 170 * hs_parse_longdate 171 * 172 * Parse the long 'user-oriented' date into a Unix timeval. 173 * This is the date format used in the Volume Descriptor. 174 * 175 * If the date is not representable, make something up. 176 */ 177 void 178 hs_parse_longdate(dp, tvp) 179 uchar_t *dp; 180 struct timeval *tvp; 181 { 182 int year, month, day, hour, minute, sec, gmtoff; 183 184 year = HSV_DATE_YEAR(dp); 185 month = HSV_DATE_MONTH(dp); 186 day = HSV_DATE_DAY(dp); 187 hour = HSV_DATE_HOUR(dp); 188 minute = HSV_DATE_MIN(dp); 189 sec = HSV_DATE_SEC(dp); 190 gmtoff = HSV_DATE_GMTOFF(dp); 191 192 tvp->tv_usec = 0; 193 if (year < THE_EPOCH) { 194 tvp->tv_sec = 0; 195 } else { 196 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 197 if (tvp->tv_sec != -1) { 198 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 199 tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000; 200 } 201 } 202 203 } 204 205 /* cumulative number of seconds per month, non-leap and leap-year versions */ 206 static time_t cum_sec[] = { 207 0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280, 208 0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500 209 }; 210 static time_t cum_sec_leap[] = { 211 0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400, 212 0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680 213 }; 214 #define SEC_PER_DAY 0x15180 215 #define SEC_PER_YEAR 0x1e13380 216 217 /* 218 * hs_date_to_gmtime 219 * 220 * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1. 221 * 222 * Returns -1 if the date is out of range. 223 */ 224 static time_t 225 hs_date_to_gmtime(year, mon, day, gmtoff) 226 int year; 227 int mon; 228 int day; 229 int gmtoff; 230 { 231 time_t sum; 232 time_t *cp; 233 int y; 234 235 if ((year < THE_EPOCH) || (year > END_OF_TIME) || 236 (mon < 1) || (mon > 12) || 237 (day < 1) || (day > 31)) 238 return (-1); 239 240 /* 241 * Figure seconds until this year and correct for leap years. 242 * Note: 2000 is a leap year but not 2100. 243 */ 244 y = year - THE_EPOCH; 245 sum = y * SEC_PER_YEAR; 246 sum += ((y + 1) / 4) * SEC_PER_DAY; 247 /* 248 * Point to the correct table for this year and 249 * add in seconds until this month. 250 */ 251 cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap; 252 sum += cp[mon - 1]; 253 /* 254 * Add in seconds until 0:00 of this day. 255 * (days-per-month validation is not done here) 256 */ 257 sum += (day - 1) * SEC_PER_DAY; 258 sum -= (gmtoff * 15 * 60); 259 return (sum); 260 } 261 262 /* 263 * Indicate whether the directory is valid. 264 */ 265 266 int 267 hsfs_valid_dir(hd) 268 struct hs_direntry *hd; 269 { 270 /* 271 * check to see if this directory is not marked as a directory. 272 * check to see if data length is zero. 273 */ 274 275 if (hd->ext_size == 0) 276 return (0); 277 278 if (hd->type != VDIR) 279 return (0); 280 281 return (1); 282 } 283 284 285 286 /* 287 * If we haven't complained about this error type yet, do. 288 */ 289 void 290 hs_log_bogus_disk_warning(fsp, errtype, data) 291 struct hsfs *fsp; 292 int errtype; 293 uint_t data; 294 { 295 296 if (fsp->hsfs_err_flags & (1 << errtype)) 297 return; /* already complained */ 298 299 cmn_err(CE_NOTE, hsfs_error[errtype].hdr_text, 300 fsp->hsfs_fsmnt); 301 302 switch (hsfs_error[errtype].n_printf_args) { 303 case 0: 304 cmn_err(CE_CONT, hsfs_error[errtype].err_text); 305 break; 306 case 1: 307 cmn_err(CE_CONT, hsfs_error[errtype].err_text, data); 308 break; 309 default: 310 /* don't currently handle more than 1 arg */ 311 cmn_err(CE_CONT, "unknown problem; internal error.\n"); 312 } 313 cmn_err(CE_CONT, 314 "Due to this error, the file system may not be correctly interpreted.\n"); 315 if (hsfs_error[errtype].multiple) 316 cmn_err(CE_CONT, 317 "Other such errors in this file system will be silently ignored.\n\n"); 318 else 319 cmn_err(CE_CONT, "\n"); 320 321 fsp->hsfs_err_flags |= (1 << errtype); 322 } 323