10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*2900Sfrankho * Common Development and Distribution License (the "License"). 6*2900Sfrankho * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 220Sstevel@tonic-gate * Miscellaneous support subroutines for High Sierra filesystem 230Sstevel@tonic-gate * 24*2900Sfrankho * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25*2900Sfrankho * Use is subject to license terms. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/param.h> 320Sstevel@tonic-gate #include <sys/time.h> 330Sstevel@tonic-gate #include <sys/cmn_err.h> 340Sstevel@tonic-gate #include <sys/systm.h> 350Sstevel@tonic-gate #include <sys/sysmacros.h> 360Sstevel@tonic-gate #include <sys/buf.h> 370Sstevel@tonic-gate #include <sys/conf.h> 380Sstevel@tonic-gate #include <sys/user.h> 390Sstevel@tonic-gate #include <sys/vfs.h> 400Sstevel@tonic-gate #include <sys/vnode.h> 410Sstevel@tonic-gate #include <sys/proc.h> 420Sstevel@tonic-gate #include <sys/debug.h> 430Sstevel@tonic-gate #include <sys/kmem.h> 440Sstevel@tonic-gate #include <sys/uio.h> 450Sstevel@tonic-gate #include <vm/hat.h> 460Sstevel@tonic-gate #include <vm/as.h> 470Sstevel@tonic-gate #include <vm/seg.h> 480Sstevel@tonic-gate #include <vm/page.h> 490Sstevel@tonic-gate #include <vm/pvn.h> 500Sstevel@tonic-gate #include <vm/seg_map.h> 510Sstevel@tonic-gate #include <sys/swap.h> 520Sstevel@tonic-gate #include <vm/seg_kmem.h> 530Sstevel@tonic-gate 540Sstevel@tonic-gate #include <sys/fs/hsfs_spec.h> 550Sstevel@tonic-gate #include <sys/fs/hsfs_node.h> 560Sstevel@tonic-gate #include <sys/fs/hsfs_impl.h> 570Sstevel@tonic-gate 580Sstevel@tonic-gate #define THE_EPOCH 1970 590Sstevel@tonic-gate #define END_OF_TIME 2099 600Sstevel@tonic-gate 610Sstevel@tonic-gate #ifdef __STDC__ 620Sstevel@tonic-gate static time_t hs_date_to_gmtime(int year, int mon, int day, int gmtoff); 630Sstevel@tonic-gate #else 640Sstevel@tonic-gate static time_t hs_date_to_gmtime(); 650Sstevel@tonic-gate #endif 660Sstevel@tonic-gate 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * Table used in logging non-fatal errors which should be recorded 690Sstevel@tonic-gate * once per mount. Indexed by HSFS_ERR values (defined in hsfs_node.h). 700Sstevel@tonic-gate */ 710Sstevel@tonic-gate struct hsfs_error { 720Sstevel@tonic-gate char *hdr_text; /* msg prefix: general error type */ 730Sstevel@tonic-gate /* must contain %s for mnt pt */ 740Sstevel@tonic-gate char *err_text; /* specific error message */ 750Sstevel@tonic-gate uchar_t multiple; /* > 1 such error per fs possible? */ 760Sstevel@tonic-gate uchar_t n_printf_args; /* if err_text printf-like, # addtl args */ 770Sstevel@tonic-gate } hsfs_error[] = { 780Sstevel@tonic-gate /* HSFS_ERR_TRAILING_JUNK */ 79*2900Sfrankho "hsfs: Warning: the file system mounted on %s " 800Sstevel@tonic-gate "does not conform to the ISO-9660 specification:", 81*2900Sfrankho "trailing blanks or null characters in file or directory name.\n", 820Sstevel@tonic-gate 1, 0, 830Sstevel@tonic-gate /* HSFS_ERR_LOWER_CASE_NM */ 84*2900Sfrankho "hsfs: Warning: the file system mounted on %s " 85*2900Sfrankho "does not conform to the ISO-9660 specification:", 86*2900Sfrankho "lower case characters in file or directory name.\n", 870Sstevel@tonic-gate 1, 0, 880Sstevel@tonic-gate /* HSFS_ERR_BAD_ROOT_DIR */ 89*2900Sfrankho "hsfs: Warning: the file system mounted on %s " 900Sstevel@tonic-gate "does not conform to the ISO-9660 specification:", 91*2900Sfrankho "invalid root directory.\n", 920Sstevel@tonic-gate 0, 0, 930Sstevel@tonic-gate /* HSFS_ERR_UNSUP_TYPE */ 94*2900Sfrankho "hsfs: Warning: the file system mounted on %s " 950Sstevel@tonic-gate "contains a file or directory with an unsupported type:", 960Sstevel@tonic-gate " 0x%x.\n", 970Sstevel@tonic-gate 1, 1, 980Sstevel@tonic-gate /* HSFS_ERR_BAD_FILE_LEN */ 99*2900Sfrankho "hsfs: Warning: file system mounted on %s " 1000Sstevel@tonic-gate "does not conform to the ISO-9660 specification:", 101*2900Sfrankho "file name length greater than max allowed\n", 102*2900Sfrankho 1, 0, 103*2900Sfrankho /* HSFS_ERR_BAD_JOLIET_FILE_LEN */ 104*2900Sfrankho "hsfs: Warning: file system mounted on %s " 105*2900Sfrankho "does not conform to the Joliet specification:", 106*2900Sfrankho "file name length greater than max allowed\n", 107*2900Sfrankho 1, 0, 108*2900Sfrankho /* HSFS_ERR_TRUNC_JOLIET_FILE_LEN */ 109*2900Sfrankho "hsfs: Warning: file system mounted on %s " 110*2900Sfrankho "does not conform to the Joliet specification:", 111*2900Sfrankho "file name length greater than MAXNAMELEN (truncated)\n", 112*2900Sfrankho 1, 0, 113*2900Sfrankho /* HSFS_ERR_BAD_DIR_ENTRY */ 114*2900Sfrankho "hsfs: Warning: file system mounted on %s " 115*2900Sfrankho "has inconsistent data:", 116*2900Sfrankho "invalid directory or file name length (ignored)\n", 1170Sstevel@tonic-gate 1, 0, 1180Sstevel@tonic-gate }; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate /* 1230Sstevel@tonic-gate * hs_parse_dirdate 1240Sstevel@tonic-gate * 1250Sstevel@tonic-gate * Parse the short 'directory-format' date into a Unix timeval. 1260Sstevel@tonic-gate * This is the date format used in Directory Entries. 1270Sstevel@tonic-gate * 1280Sstevel@tonic-gate * If the date is not representable, make something up. 1290Sstevel@tonic-gate */ 1300Sstevel@tonic-gate void 1310Sstevel@tonic-gate hs_parse_dirdate(dp, tvp) 1320Sstevel@tonic-gate uchar_t *dp; 1330Sstevel@tonic-gate struct timeval *tvp; 1340Sstevel@tonic-gate { 1350Sstevel@tonic-gate int year, month, day, hour, minute, sec, gmtoff; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate year = HDE_DATE_YEAR(dp); 1380Sstevel@tonic-gate month = HDE_DATE_MONTH(dp); 1390Sstevel@tonic-gate day = HDE_DATE_DAY(dp); 1400Sstevel@tonic-gate hour = HDE_DATE_HOUR(dp); 1410Sstevel@tonic-gate minute = HDE_DATE_MIN(dp); 1420Sstevel@tonic-gate sec = HDE_DATE_SEC(dp); 1430Sstevel@tonic-gate gmtoff = HDE_DATE_GMTOFF(dp); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate tvp->tv_usec = 0; 1460Sstevel@tonic-gate if (year < THE_EPOCH) { 1470Sstevel@tonic-gate tvp->tv_sec = 0; 1480Sstevel@tonic-gate } else { 1490Sstevel@tonic-gate tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 1500Sstevel@tonic-gate if (tvp->tv_sec != -1) { 1510Sstevel@tonic-gate tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate return; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate /* 1600Sstevel@tonic-gate * hs_parse_longdate 1610Sstevel@tonic-gate * 1620Sstevel@tonic-gate * Parse the long 'user-oriented' date into a Unix timeval. 1630Sstevel@tonic-gate * This is the date format used in the Volume Descriptor. 1640Sstevel@tonic-gate * 1650Sstevel@tonic-gate * If the date is not representable, make something up. 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate void 1680Sstevel@tonic-gate hs_parse_longdate(dp, tvp) 1690Sstevel@tonic-gate uchar_t *dp; 1700Sstevel@tonic-gate struct timeval *tvp; 1710Sstevel@tonic-gate { 1720Sstevel@tonic-gate int year, month, day, hour, minute, sec, gmtoff; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate year = HSV_DATE_YEAR(dp); 1750Sstevel@tonic-gate month = HSV_DATE_MONTH(dp); 1760Sstevel@tonic-gate day = HSV_DATE_DAY(dp); 1770Sstevel@tonic-gate hour = HSV_DATE_HOUR(dp); 1780Sstevel@tonic-gate minute = HSV_DATE_MIN(dp); 1790Sstevel@tonic-gate sec = HSV_DATE_SEC(dp); 1800Sstevel@tonic-gate gmtoff = HSV_DATE_GMTOFF(dp); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate tvp->tv_usec = 0; 1830Sstevel@tonic-gate if (year < THE_EPOCH) { 1840Sstevel@tonic-gate tvp->tv_sec = 0; 1850Sstevel@tonic-gate } else { 1860Sstevel@tonic-gate tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 1870Sstevel@tonic-gate if (tvp->tv_sec != -1) { 1880Sstevel@tonic-gate tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 1890Sstevel@tonic-gate tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000; 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate /* cumulative number of seconds per month, non-leap and leap-year versions */ 1960Sstevel@tonic-gate static time_t cum_sec[] = { 1970Sstevel@tonic-gate 0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280, 1980Sstevel@tonic-gate 0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500 1990Sstevel@tonic-gate }; 2000Sstevel@tonic-gate static time_t cum_sec_leap[] = { 2010Sstevel@tonic-gate 0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400, 2020Sstevel@tonic-gate 0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680 2030Sstevel@tonic-gate }; 2040Sstevel@tonic-gate #define SEC_PER_DAY 0x15180 2050Sstevel@tonic-gate #define SEC_PER_YEAR 0x1e13380 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate /* 2080Sstevel@tonic-gate * hs_date_to_gmtime 2090Sstevel@tonic-gate * 2100Sstevel@tonic-gate * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1. 2110Sstevel@tonic-gate * 2120Sstevel@tonic-gate * Returns -1 if the date is out of range. 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate static time_t 2150Sstevel@tonic-gate hs_date_to_gmtime(year, mon, day, gmtoff) 2160Sstevel@tonic-gate int year; 2170Sstevel@tonic-gate int mon; 2180Sstevel@tonic-gate int day; 2190Sstevel@tonic-gate int gmtoff; 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate time_t sum; 2220Sstevel@tonic-gate time_t *cp; 2230Sstevel@tonic-gate int y; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate if ((year < THE_EPOCH) || (year > END_OF_TIME) || 2260Sstevel@tonic-gate (mon < 1) || (mon > 12) || 2270Sstevel@tonic-gate (day < 1) || (day > 31)) 2280Sstevel@tonic-gate return (-1); 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * Figure seconds until this year and correct for leap years. 2320Sstevel@tonic-gate * Note: 2000 is a leap year but not 2100. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate y = year - THE_EPOCH; 2350Sstevel@tonic-gate sum = y * SEC_PER_YEAR; 2360Sstevel@tonic-gate sum += ((y + 1) / 4) * SEC_PER_DAY; 2370Sstevel@tonic-gate /* 2380Sstevel@tonic-gate * Point to the correct table for this year and 2390Sstevel@tonic-gate * add in seconds until this month. 2400Sstevel@tonic-gate */ 2410Sstevel@tonic-gate cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap; 2420Sstevel@tonic-gate sum += cp[mon - 1]; 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * Add in seconds until 0:00 of this day. 2450Sstevel@tonic-gate * (days-per-month validation is not done here) 2460Sstevel@tonic-gate */ 2470Sstevel@tonic-gate sum += (day - 1) * SEC_PER_DAY; 2480Sstevel@tonic-gate sum -= (gmtoff * 15 * 60); 2490Sstevel@tonic-gate return (sum); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * Indicate whether the directory is valid. 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate int 2570Sstevel@tonic-gate hsfs_valid_dir(hd) 2580Sstevel@tonic-gate struct hs_direntry *hd; 2590Sstevel@tonic-gate { 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * check to see if this directory is not marked as a directory. 2620Sstevel@tonic-gate * check to see if data length is zero. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate if (hd->ext_size == 0) 2660Sstevel@tonic-gate return (0); 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate if (hd->type != VDIR) 2690Sstevel@tonic-gate return (0); 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate return (1); 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate /* 2770Sstevel@tonic-gate * If we haven't complained about this error type yet, do. 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate void 2800Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, errtype, data) 2810Sstevel@tonic-gate struct hsfs *fsp; 2820Sstevel@tonic-gate int errtype; 2830Sstevel@tonic-gate uint_t data; 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate if (fsp->hsfs_err_flags & (1 << errtype)) 2870Sstevel@tonic-gate return; /* already complained */ 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate cmn_err(CE_NOTE, hsfs_error[errtype].hdr_text, 2900Sstevel@tonic-gate fsp->hsfs_fsmnt); 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate switch (hsfs_error[errtype].n_printf_args) { 2930Sstevel@tonic-gate case 0: 2940Sstevel@tonic-gate cmn_err(CE_CONT, hsfs_error[errtype].err_text); 2950Sstevel@tonic-gate break; 2960Sstevel@tonic-gate case 1: 2970Sstevel@tonic-gate cmn_err(CE_CONT, hsfs_error[errtype].err_text, data); 2980Sstevel@tonic-gate break; 2990Sstevel@tonic-gate default: 3000Sstevel@tonic-gate /* don't currently handle more than 1 arg */ 3010Sstevel@tonic-gate cmn_err(CE_CONT, "unknown problem; internal error.\n"); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate cmn_err(CE_CONT, 3040Sstevel@tonic-gate "Due to this error, the file system may not be correctly interpreted.\n"); 3050Sstevel@tonic-gate if (hsfs_error[errtype].multiple) 3060Sstevel@tonic-gate cmn_err(CE_CONT, 3070Sstevel@tonic-gate "Other such errors in this file system will be silently ignored.\n\n"); 3080Sstevel@tonic-gate else 3090Sstevel@tonic-gate cmn_err(CE_CONT, "\n"); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate fsp->hsfs_err_flags |= (1 << errtype); 3120Sstevel@tonic-gate } 313