xref: /illumos-gate/usr/src/uts/common/fs/hsfs/hsfs_subr.c (revision 3db86aab)
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