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