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