1 /* $FreeBSD$ */ 2 /* $NetBSD: msdosfs_conv.c,v 1.25 1997/11/17 15:36:40 ws Exp $ */ 3 4 /*- 5 * Copyright (C) 1995, 1997 Wolfgang Solfrank. 6 * Copyright (C) 1995, 1997 TooLs GmbH. 7 * All rights reserved. 8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by TooLs GmbH. 21 * 4. The name of TooLs GmbH may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /*- 36 * Written by Paul Popelka (paulp@uts.amdahl.com) 37 * 38 * You can do anything you want with this software, just don't say you wrote 39 * it, and don't remove this notice. 40 * 41 * This software is provided "as is". 42 * 43 * The author supplies this software to be publicly redistributed on the 44 * understanding that the author is not responsible for the correct 45 * functioning of this software in any circumstances and is not liable for 46 * any damages caused by this software. 47 * 48 * October 1992 49 */ 50 51 /* 52 * System include files. 53 */ 54 #include <sys/param.h> 55 #include <sys/time.h> 56 #include <sys/kernel.h> /* defines tz */ 57 #include <sys/systm.h> 58 #include <machine/clock.h> 59 #include <sys/dirent.h> 60 #include <sys/iconv.h> 61 #include <sys/mount.h> 62 #include <sys/malloc.h> 63 64 extern struct iconv_functions *msdosfs_iconv; 65 66 /* 67 * MSDOSFS include files. 68 */ 69 #include <fs/msdosfs/bpb.h> 70 #include <fs/msdosfs/msdosfsmount.h> 71 #include <fs/msdosfs/direntry.h> 72 73 /* 74 * Total number of days that have passed for each month in a regular year. 75 */ 76 static u_short regyear[] = { 77 31, 59, 90, 120, 151, 181, 78 212, 243, 273, 304, 334, 365 79 }; 80 81 /* 82 * Total number of days that have passed for each month in a leap year. 83 */ 84 static u_short leapyear[] = { 85 31, 60, 91, 121, 152, 182, 86 213, 244, 274, 305, 335, 366 87 }; 88 89 /* 90 * Variables used to remember parts of the last time conversion. Maybe we 91 * can avoid a full conversion. 92 */ 93 static u_long lasttime; 94 static u_long lastday; 95 static u_short lastddate; 96 static u_short lastdtime; 97 98 static int mbsadjpos(const char **, size_t, size_t, int, int, void *handle); 99 static u_int16_t dos2unixchr(const u_char **, size_t *, int, struct msdosfsmount *); 100 static u_int16_t unix2doschr(const u_char **, size_t *, struct msdosfsmount *); 101 static u_int16_t win2unixchr(u_int16_t, struct msdosfsmount *); 102 static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *); 103 104 struct mbnambuf { 105 char * p; 106 size_t n; 107 }; 108 static struct mbnambuf subent[WIN_MAXSUBENTRIES]; 109 110 /* 111 * Convert the unix version of time to dos's idea of time to be used in 112 * file timestamps. The passed in unix time is assumed to be in GMT. 113 */ 114 void 115 unix2dostime(tsp, ddp, dtp, dhp) 116 struct timespec *tsp; 117 u_int16_t *ddp; 118 u_int16_t *dtp; 119 u_int8_t *dhp; 120 { 121 u_long t; 122 u_long days; 123 u_long inc; 124 u_long year; 125 u_long month; 126 u_short *months; 127 128 /* 129 * If the time from the last conversion is the same as now, then 130 * skip the computations and use the saved result. 131 */ 132 t = tsp->tv_sec - (tz_minuteswest * 60) 133 - (wall_cmos_clock ? adjkerntz : 0); 134 /* - daylight savings time correction */ 135 t &= ~1; 136 if (lasttime != t) { 137 lasttime = t; 138 lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT) 139 + (((t / 60) % 60) << DT_MINUTES_SHIFT) 140 + (((t / 3600) % 24) << DT_HOURS_SHIFT); 141 142 /* 143 * If the number of days since 1970 is the same as the last 144 * time we did the computation then skip all this leap year 145 * and month stuff. 146 */ 147 days = t / (24 * 60 * 60); 148 if (days != lastday) { 149 lastday = days; 150 for (year = 1970;; year++) { 151 inc = year & 0x03 ? 365 : 366; 152 if (days < inc) 153 break; 154 days -= inc; 155 } 156 months = year & 0x03 ? regyear : leapyear; 157 for (month = 0; days >= months[month]; month++) 158 ; 159 if (month > 0) 160 days -= months[month - 1]; 161 lastddate = ((days + 1) << DD_DAY_SHIFT) 162 + ((month + 1) << DD_MONTH_SHIFT); 163 /* 164 * Remember dos's idea of time is relative to 1980. 165 * unix's is relative to 1970. If somehow we get a 166 * time before 1980 then don't give totally crazy 167 * results. 168 */ 169 if (year > 1980) 170 lastddate += (year - 1980) << DD_YEAR_SHIFT; 171 } 172 } 173 if (dtp) 174 *dtp = lastdtime; 175 if (dhp) 176 *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000; 177 178 *ddp = lastddate; 179 } 180 181 /* 182 * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that 183 * interval there were 8 regular years and 2 leap years. 184 */ 185 #define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60)) 186 187 static u_short lastdosdate; 188 static u_long lastseconds; 189 190 /* 191 * Convert from dos' idea of time to unix'. This will probably only be 192 * called from the stat(), and fstat() system calls and so probably need 193 * not be too efficient. 194 */ 195 void 196 dos2unixtime(dd, dt, dh, tsp) 197 u_int dd; 198 u_int dt; 199 u_int dh; 200 struct timespec *tsp; 201 { 202 u_long seconds; 203 u_long month; 204 u_long year; 205 u_long days; 206 u_short *months; 207 208 if (dd == 0) { 209 /* 210 * Uninitialized field, return the epoch. 211 */ 212 tsp->tv_sec = 0; 213 tsp->tv_nsec = 0; 214 return; 215 } 216 seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1) 217 + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60 218 + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600 219 + dh / 100; 220 /* 221 * If the year, month, and day from the last conversion are the 222 * same then use the saved value. 223 */ 224 if (lastdosdate != dd) { 225 lastdosdate = dd; 226 days = 0; 227 year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT; 228 days = year * 365; 229 days += year / 4 + 1; /* add in leap days */ 230 if ((year & 0x03) == 0) 231 days--; /* if year is a leap year */ 232 months = year & 0x03 ? regyear : leapyear; 233 month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT; 234 if (month < 1 || month > 12) { 235 printf("dos2unixtime(): month value out of range (%ld)\n", 236 month); 237 month = 1; 238 } 239 if (month > 1) 240 days += months[month - 2]; 241 days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1; 242 lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980; 243 } 244 tsp->tv_sec = seconds + lastseconds + (tz_minuteswest * 60) 245 + adjkerntz; 246 /* + daylight savings time correction */ 247 tsp->tv_nsec = (dh % 100) * 10000000; 248 } 249 250 /* 251 * 0 - character disallowed in long file name. 252 * 1 - character should be replaced by '_' in DOS file name, 253 * and generation number inserted. 254 * 2 - character ('.' and ' ') should be skipped in DOS file name, 255 * and generation number inserted. 256 */ 257 static u_char 258 unix2dos[256] = { 259 /* iso8859-1 -> cp850 */ 260 0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */ 261 0, 0, 0, 0, 0, 0, 0, 0, /* 08-0f */ 262 0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */ 263 0, 0, 0, 0, 0, 0, 0, 0, /* 18-1f */ 264 2, 0x21, 0, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */ 265 0x28, 0x29, 0, 1, 1, 0x2d, 2, 0, /* 28-2f */ 266 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */ 267 0x38, 0x39, 0, 1, 0, 1, 0, 0, /* 38-3f */ 268 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */ 269 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */ 270 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */ 271 0x58, 0x59, 0x5a, 1, 0, 1, 0x5e, 0x5f, /* 58-5f */ 272 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 60-67 */ 273 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 68-6f */ 274 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 70-77 */ 275 0x58, 0x59, 0x5a, 0x7b, 0, 0x7d, 0x7e, 0, /* 78-7f */ 276 0, 0, 0, 0, 0, 0, 0, 0, /* 80-87 */ 277 0, 0, 0, 0, 0, 0, 0, 0, /* 88-8f */ 278 0, 0, 0, 0, 0, 0, 0, 0, /* 90-97 */ 279 0, 0, 0, 0, 0, 0, 0, 0, /* 98-9f */ 280 0, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */ 281 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */ 282 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */ 283 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */ 284 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */ 285 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */ 286 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */ 287 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */ 288 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */ 289 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */ 290 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */ 291 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */ 292 }; 293 294 static u_char 295 dos2unix[256] = { 296 /* cp850 -> iso8859-1 */ 297 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 00-07 */ 298 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 08-0f */ 299 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 10-17 */ 300 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 18-1f */ 301 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */ 302 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */ 303 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */ 304 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */ 305 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */ 306 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */ 307 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */ 308 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */ 309 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */ 310 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */ 311 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */ 312 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */ 313 0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7, /* 80-87 */ 314 0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5, /* 88-8f */ 315 0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9, /* 90-97 */ 316 0xff, 0xd6, 0xdc, 0xf8, 0xa3, 0xd8, 0xd7, 0x3f, /* 98-9f */ 317 0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba, /* a0-a7 */ 318 0xbf, 0xae, 0xac, 0xbd, 0xbc, 0xa1, 0xab, 0xbb, /* a8-af */ 319 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xc1, 0xc2, 0xc0, /* b0-b7 */ 320 0xa9, 0x3f, 0x3f, 0x3f, 0x3f, 0xa2, 0xa5, 0x3f, /* b8-bf */ 321 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xe3, 0xc3, /* c0-c7 */ 322 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xa4, /* c8-cf */ 323 0xf0, 0xd0, 0xca, 0xcb, 0xc8, 0x3f, 0xcd, 0xce, /* d0-d7 */ 324 0xcf, 0x3f, 0x3f, 0x3f, 0x3f, 0xa6, 0xcc, 0x3f, /* d8-df */ 325 0xd3, 0xdf, 0xd4, 0xd2, 0xf5, 0xd5, 0xb5, 0xfe, /* e0-e7 */ 326 0xde, 0xda, 0xdb, 0xd9, 0xfd, 0xdd, 0xaf, 0x3f, /* e8-ef */ 327 0xad, 0xb1, 0x3f, 0xbe, 0xb6, 0xa7, 0xf7, 0xb8, /* f0-f7 */ 328 0xb0, 0xa8, 0xb7, 0xb9, 0xb3, 0xb2, 0x3f, 0x3f, /* f8-ff */ 329 }; 330 331 static u_char 332 u2l[256] = { 333 /* tolower */ 334 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */ 335 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */ 336 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */ 337 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */ 338 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */ 339 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */ 340 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */ 341 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */ 342 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 40-47 */ 343 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 48-4f */ 344 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 50-57 */ 345 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */ 346 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */ 347 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */ 348 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */ 349 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */ 350 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */ 351 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */ 352 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */ 353 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */ 354 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */ 355 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */ 356 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */ 357 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */ 358 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */ 359 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */ 360 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */ 361 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */ 362 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */ 363 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */ 364 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */ 365 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */ 366 }; 367 368 static u_char 369 l2u[256] = { 370 /* toupper */ 371 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */ 372 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */ 373 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */ 374 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */ 375 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */ 376 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */ 377 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */ 378 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */ 379 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 40-47 */ 380 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 48-4f */ 381 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 50-57 */ 382 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */ 383 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */ 384 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */ 385 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */ 386 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */ 387 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */ 388 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */ 389 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */ 390 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */ 391 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */ 392 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */ 393 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */ 394 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */ 395 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */ 396 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */ 397 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */ 398 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */ 399 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */ 400 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */ 401 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */ 402 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */ 403 }; 404 405 /* 406 * DOS filenames are made of 2 parts, the name part and the extension part. 407 * The name part is 8 characters long and the extension part is 3 408 * characters long. They may contain trailing blanks if the name or 409 * extension are not long enough to fill their respective fields. 410 */ 411 412 /* 413 * Convert a DOS filename to a unix filename. And, return the number of 414 * characters in the resulting unix filename excluding the terminating 415 * null. 416 */ 417 int 418 dos2unixfn(dn, un, lower, pmp) 419 u_char dn[11]; 420 u_char *un; 421 int lower; 422 struct msdosfsmount *pmp; 423 { 424 size_t i; 425 int thislong = 0; 426 u_int16_t c; 427 428 /* 429 * If first char of the filename is SLOT_E5 (0x05), then the real 430 * first char of the filename should be 0xe5. But, they couldn't 431 * just have a 0xe5 mean 0xe5 because that is used to mean a freed 432 * directory slot. Another dos quirk. 433 */ 434 if (*dn == SLOT_E5) 435 *dn = 0xe5; 436 437 /* 438 * Copy the name portion into the unix filename string. 439 */ 440 for (i = 8; i > 0 && *dn != ' ';) { 441 c = dos2unixchr((const u_char **)&dn, &i, lower, pmp); 442 if (c & 0xff00) { 443 *un++ = c >> 8; 444 thislong++; 445 } 446 *un++ = c; 447 thislong++; 448 } 449 dn += i; 450 451 /* 452 * Now, if there is an extension then put in a period and copy in 453 * the extension. 454 */ 455 if (*dn != ' ') { 456 *un++ = '.'; 457 thislong++; 458 for (i = 3; i > 0 && *dn != ' ';) { 459 c = dos2unixchr((const u_char **)&dn, &i, lower, pmp); 460 if (c & 0xff00) { 461 *un++ = c >> 8; 462 thislong++; 463 } 464 *un++ = c; 465 thislong++; 466 } 467 } 468 *un++ = 0; 469 470 return (thislong); 471 } 472 473 /* 474 * Convert a unix filename to a DOS filename according to Win95 rules. 475 * If applicable and gen is not 0, it is inserted into the converted 476 * filename as a generation number. 477 * Returns 478 * 0 if name couldn't be converted 479 * 1 if the converted name is the same as the original 480 * (no long filename entry necessary for Win95) 481 * 2 if conversion was successful 482 * 3 if conversion was successful and generation number was inserted 483 */ 484 int 485 unix2dosfn(un, dn, unlen, gen, pmp) 486 const u_char *un; 487 u_char dn[12]; 488 size_t unlen; 489 u_int gen; 490 struct msdosfsmount *pmp; 491 { 492 ssize_t i, j; 493 int l; 494 int conv = 1; 495 const u_char *cp, *dp, *dp1; 496 u_char gentext[6], *wcp; 497 u_int16_t c; 498 499 /* 500 * Fill the dos filename string with blanks. These are DOS's pad 501 * characters. 502 */ 503 for (i = 0; i < 11; i++) 504 dn[i] = ' '; 505 dn[11] = 0; 506 507 /* 508 * The filenames "." and ".." are handled specially, since they 509 * don't follow dos filename rules. 510 */ 511 if (un[0] == '.' && unlen == 1) { 512 dn[0] = '.'; 513 return gen <= 1; 514 } 515 if (un[0] == '.' && un[1] == '.' && unlen == 2) { 516 dn[0] = '.'; 517 dn[1] = '.'; 518 return gen <= 1; 519 } 520 521 /* 522 * Filenames with only blanks and dots are not allowed! 523 */ 524 for (cp = un, i = unlen; --i >= 0; cp++) 525 if (*cp != ' ' && *cp != '.') 526 break; 527 if (i < 0) 528 return 0; 529 530 531 /* 532 * Filenames with some characters are not allowed! 533 */ 534 for (cp = un, i = unlen; i > 0;) 535 if (unix2doschr(&cp, (size_t *)&i, pmp) == 0) 536 return 0; 537 538 /* 539 * Now find the extension 540 * Note: dot as first char doesn't start extension 541 * and trailing dots and blanks are ignored 542 * Note(2003/7): It seems recent Windows has 543 * defferent rule than this code, that Windows 544 * ignores all dots before extension, and use all 545 * chars as filename except for dots. 546 */ 547 dp = dp1 = 0; 548 for (cp = un + 1, i = unlen - 1; --i >= 0;) { 549 switch (*cp++) { 550 case '.': 551 if (!dp1) 552 dp1 = cp; 553 break; 554 case ' ': 555 break; 556 default: 557 if (dp1) 558 dp = dp1; 559 dp1 = 0; 560 break; 561 } 562 } 563 564 /* 565 * Now convert it (this part is for extension) 566 */ 567 if (dp) { 568 if (dp1) 569 l = dp1 - dp; 570 else 571 l = unlen - (dp - un); 572 for (cp = dp, i = l, j = 8; i > 0 && j < 11; j++) { 573 c = unix2doschr(&cp, (size_t *)&i, pmp); 574 if (c & 0xff00) { 575 dn[j] = c >> 8; 576 if (++j < 11) { 577 dn[j] = c; 578 continue; 579 } else { 580 conv = 3; 581 dn[j-1] = ' '; 582 break; 583 } 584 } else { 585 dn[j] = c; 586 } 587 if (*(cp - 1) != dn[j] && conv != 3) 588 conv = 2; 589 if (dn[j] == 1) { 590 conv = 3; 591 dn[j] = '_'; 592 } 593 if (dn[j] == 2) { 594 conv = 3; 595 dn[j--] = ' '; 596 } 597 } 598 if (i > 0) 599 conv = 3; 600 dp--; 601 } else { 602 for (dp = cp; *--dp == ' ' || *dp == '.';); 603 dp++; 604 } 605 606 /* 607 * Now convert the rest of the name 608 */ 609 for (i = dp - un, j = 0; un < dp && j < 8; j++) { 610 c = unix2doschr(&un, &i, pmp); 611 if (c & 0xff00) { 612 dn[j] = c >> 8; 613 if (++j < 8) { 614 dn[j] = c; 615 continue; 616 } else { 617 conv = 3; 618 dn[j-1] = ' '; 619 break; 620 } 621 } else { 622 dn[j] = c; 623 } 624 if (*(un - 1) != dn[j] && conv != 3) 625 conv = 2; 626 if (dn[j] == 1) { 627 conv = 3; 628 dn[j] = '_'; 629 } 630 if (dn[j] == 2) { 631 conv = 3; 632 dn[j--] = ' '; 633 } 634 } 635 if (un < dp) 636 conv = 3; 637 /* 638 * If we didn't have any chars in filename, 639 * generate a default 640 */ 641 if (!j) 642 dn[0] = '_'; 643 644 /* 645 * If there wasn't any char dropped, 646 * there is no place for generation numbers 647 */ 648 if (conv != 3) { 649 if (gen > 1) 650 conv = 0; 651 goto done; 652 } 653 654 /* 655 * Now insert the generation number into the filename part 656 */ 657 if (gen == 0) 658 goto done; 659 for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10) 660 *--wcp = gen % 10 + '0'; 661 if (gen) { 662 conv = 0; 663 goto done; 664 } 665 for (i = 8; dn[--i] == ' ';); 666 i++; 667 if (gentext + sizeof(gentext) - wcp + 1 > 8 - i) 668 i = 8 - (gentext + sizeof(gentext) - wcp + 1); 669 /* 670 * Correct posision to where insert the generation number 671 */ 672 cp = dn; 673 i -= mbsadjpos((const char**)&cp, i, unlen, 1, pmp->pm_flags, pmp->pm_d2u); 674 675 dn[i++] = '~'; 676 while (wcp < gentext + sizeof(gentext)) 677 dn[i++] = *wcp++; 678 679 /* 680 * Tail of the filename should be space 681 */ 682 while (i < 8) 683 dn[i++] = ' '; 684 conv = 3; 685 686 done: 687 /* 688 * The first character cannot be E5, 689 * because that means a deleted entry 690 */ 691 if (dn[0] == 0xe5) 692 dn[0] = SLOT_E5; 693 694 return conv; 695 } 696 697 /* 698 * Create a Win95 long name directory entry 699 * Note: assumes that the filename is valid, 700 * i.e. doesn't consist solely of blanks and dots 701 */ 702 int 703 unix2winfn(un, unlen, wep, cnt, chksum, pmp) 704 const u_char *un; 705 size_t unlen; 706 struct winentry *wep; 707 int cnt; 708 int chksum; 709 struct msdosfsmount *pmp; 710 { 711 u_int8_t *wcp; 712 int i, end; 713 u_int16_t code; 714 715 /* 716 * Drop trailing blanks and dots 717 */ 718 unlen = winLenFixup(un, unlen); 719 720 /* 721 * Cut *un for this slot 722 */ 723 unlen = mbsadjpos((const char **)&un, unlen, (cnt - 1) * WIN_CHARS, 2, 724 pmp->pm_flags, pmp->pm_u2w); 725 726 /* 727 * Initialize winentry to some useful default 728 */ 729 for (wcp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *wcp++ = 0xff); 730 wep->weCnt = cnt; 731 wep->weAttributes = ATTR_WIN95; 732 wep->weReserved1 = 0; 733 wep->weChksum = chksum; 734 wep->weReserved2 = 0; 735 736 /* 737 * Now convert the filename parts 738 */ 739 end = 0; 740 for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0 && !end;) { 741 code = unix2winchr(&un, &unlen, 0, pmp); 742 *wcp++ = code; 743 *wcp++ = code >> 8; 744 if (!code) 745 end = WIN_LAST; 746 } 747 for (wcp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0 && !end;) { 748 code = unix2winchr(&un, &unlen, 0, pmp); 749 *wcp++ = code; 750 *wcp++ = code >> 8; 751 if (!code) 752 end = WIN_LAST; 753 } 754 for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0 && !end;) { 755 code = unix2winchr(&un, &unlen, 0, pmp); 756 *wcp++ = code; 757 *wcp++ = code >> 8; 758 if (!code) 759 end = WIN_LAST; 760 } 761 if (*un == '\0') 762 end = WIN_LAST; 763 wep->weCnt |= end; 764 return !end; 765 } 766 767 /* 768 * Compare our filename to the one in the Win95 entry 769 * Returns the checksum or -1 if no match 770 */ 771 int 772 winChkName(un, unlen, chksum, pmp) 773 const u_char *un; 774 size_t unlen; 775 int chksum; 776 struct msdosfsmount *pmp; 777 { 778 size_t len; 779 u_int16_t c1, c2; 780 u_char *np; 781 struct dirent dirbuf; 782 783 /* 784 * We alread have winentry in mbnambuf 785 */ 786 if (!mbnambuf_flush(&dirbuf) || !dirbuf.d_namlen) 787 return -1; 788 789 #ifdef MSDOSFS_DEBUG 790 printf("winChkName(): un=%s:%d,d_name=%s:%d\n", un, unlen, 791 dirbuf.d_name, 792 dirbuf.d_namlen); 793 #endif 794 795 /* 796 * Compare the name parts 797 */ 798 len = dirbuf.d_namlen; 799 if (unlen != len) 800 return -2; 801 802 for (np = dirbuf.d_name; unlen > 0 && len > 0;) { 803 /* 804 * Comparison must be case insensitive, because FAT disallows 805 * to look up or create files in case sensitive even when 806 * it's a long file name. 807 */ 808 c1 = unix2winchr((const u_char **)&np, &len, LCASE_BASE, pmp); 809 c2 = unix2winchr(&un, &unlen, LCASE_BASE, pmp); 810 if (c1 != c2) 811 return -2; 812 } 813 return chksum; 814 } 815 816 /* 817 * Convert Win95 filename to dirbuf. 818 * Returns the checksum or -1 if impossible 819 */ 820 int 821 win2unixfn(wep, chksum, pmp) 822 struct winentry *wep; 823 int chksum; 824 struct msdosfsmount *pmp; 825 { 826 u_int8_t *cp; 827 u_int8_t *np, name[WIN_CHARS * 2 + 1]; 828 u_int16_t code; 829 int i; 830 831 if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS) 832 || !(wep->weCnt&WIN_CNT)) 833 return -1; 834 835 /* 836 * First compare checksums 837 */ 838 if (wep->weCnt&WIN_LAST) { 839 chksum = wep->weChksum; 840 } else if (chksum != wep->weChksum) 841 chksum = -1; 842 if (chksum == -1) 843 return -1; 844 845 /* 846 * Convert the name parts 847 */ 848 np = name; 849 for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) { 850 code = (cp[1] << 8) | cp[0]; 851 switch (code) { 852 case 0: 853 *np = '\0'; 854 mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); 855 return chksum; 856 case '/': 857 *np = '\0'; 858 return -1; 859 default: 860 code = win2unixchr(code, pmp); 861 if (code & 0xff00) 862 *np++ = code >> 8; 863 *np++ = code; 864 break; 865 } 866 cp += 2; 867 } 868 for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) { 869 code = (cp[1] << 8) | cp[0]; 870 switch (code) { 871 case 0: 872 *np = '\0'; 873 mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); 874 return chksum; 875 case '/': 876 *np = '\0'; 877 return -1; 878 default: 879 code = win2unixchr(code, pmp); 880 if (code & 0xff00) 881 *np++ = code >> 8; 882 *np++ = code; 883 break; 884 } 885 cp += 2; 886 } 887 for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) { 888 code = (cp[1] << 8) | cp[0]; 889 switch (code) { 890 case 0: 891 *np = '\0'; 892 mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); 893 return chksum; 894 case '/': 895 *np = '\0'; 896 return -1; 897 default: 898 code = win2unixchr(code, pmp); 899 if (code & 0xff00) 900 *np++ = code >> 8; 901 *np++ = code; 902 break; 903 } 904 cp += 2; 905 } 906 *np = '\0'; 907 mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1); 908 return chksum; 909 } 910 911 /* 912 * Compute the unrolled checksum of a DOS filename for Win95 LFN use. 913 */ 914 u_int8_t 915 winChksum(name) 916 u_int8_t *name; 917 { 918 u_int8_t s; 919 920 s = name[0]; 921 s = ((s << 7) | (s >> 1)) + name[1]; 922 s = ((s << 7) | (s >> 1)) + name[2]; 923 s = ((s << 7) | (s >> 1)) + name[3]; 924 s = ((s << 7) | (s >> 1)) + name[4]; 925 s = ((s << 7) | (s >> 1)) + name[5]; 926 s = ((s << 7) | (s >> 1)) + name[6]; 927 s = ((s << 7) | (s >> 1)) + name[7]; 928 s = ((s << 7) | (s >> 1)) + name[8]; 929 s = ((s << 7) | (s >> 1)) + name[9]; 930 s = ((s << 7) | (s >> 1)) + name[10]; 931 932 return (s); 933 } 934 935 /* 936 * Determine the number of slots necessary for Win95 names 937 */ 938 int 939 winSlotCnt(un, unlen, pmp) 940 const u_char *un; 941 size_t unlen; 942 struct msdosfsmount *pmp; 943 { 944 size_t wlen; 945 char wn[WIN_MAXLEN * 2 + 1], *wnp; 946 947 unlen = winLenFixup(un, unlen); 948 949 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 950 wlen = WIN_MAXLEN * 2; 951 wnp = wn; 952 msdosfs_iconv->conv(pmp->pm_u2w, (const char **)&un, &unlen, &wnp, &wlen); 953 if (unlen > 0) 954 return 0; 955 return howmany(WIN_MAXLEN - wlen/2, WIN_CHARS); 956 } 957 958 if (unlen > WIN_MAXLEN) 959 return 0; 960 return howmany(unlen, WIN_CHARS); 961 } 962 963 /* 964 * Determine the number of bytes neccesary for Win95 names 965 */ 966 size_t 967 winLenFixup(un, unlen) 968 const u_char* un; 969 size_t unlen; 970 { 971 for (un += unlen; unlen > 0; unlen--) 972 if (*--un != ' ' && *un != '.') 973 break; 974 return unlen; 975 } 976 977 /* 978 * Store an area with multi byte string instr, and reterns left 979 * byte of instr and moves pointer forward. The area's size is 980 * inlen or outlen. 981 */ 982 static int 983 mbsadjpos(const char **instr, size_t inlen, size_t outlen, int weight, int flag, void *handle) 984 { 985 char *outp, outstr[outlen * weight + 1]; 986 987 if (flag & MSDOSFSMNT_KICONV && msdosfs_iconv) { 988 outp = outstr; 989 outlen *= weight; 990 msdosfs_iconv->conv(handle, instr, &inlen, &outp, &outlen); 991 return (inlen); 992 } 993 994 (*instr) += min(inlen, outlen); 995 return (inlen - min(inlen, outlen)); 996 } 997 998 /* 999 * Convert DOS char to Local char 1000 */ 1001 static u_int16_t 1002 dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp) 1003 { 1004 u_char c; 1005 char *outp, outbuf[3]; 1006 u_int16_t wc; 1007 size_t len, olen; 1008 1009 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1010 olen = len = 2; 1011 outp = outbuf; 1012 1013 if (lower & (LCASE_BASE | LCASE_EXT)) 1014 msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr, 1015 ilen, &outp, &olen, KICONV_LOWER); 1016 else 1017 msdosfs_iconv->convchr(pmp->pm_d2u, (const char **)instr, 1018 ilen, &outp, &olen); 1019 len -= olen; 1020 1021 /* 1022 * return '?' if failed to convert 1023 */ 1024 if (len == 0) { 1025 (*ilen)--; 1026 (*instr)++; 1027 return ('?'); 1028 } 1029 1030 wc = 0; 1031 while(len--) 1032 wc |= (*(outp - len - 1) & 0xff) << (len << 3); 1033 return (wc); 1034 } 1035 1036 (*ilen)--; 1037 c = *(*instr)++; 1038 c = dos2unix[c]; 1039 if (lower & (LCASE_BASE | LCASE_EXT)) 1040 c = u2l[c]; 1041 return ((u_int16_t)c); 1042 } 1043 1044 /* 1045 * Convert Local char to DOS char 1046 */ 1047 static u_int16_t 1048 unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp) 1049 { 1050 u_char c; 1051 char *up, *outp, unicode[3], outbuf[3]; 1052 u_int16_t wc; 1053 size_t len, ulen, olen; 1054 1055 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1056 /* 1057 * to hide an invisible character, using a unicode filter 1058 */ 1059 ulen = 2; 1060 len = *ilen; 1061 up = unicode; 1062 msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr, 1063 ilen, &up, &ulen); 1064 1065 /* 1066 * cannot be converted 1067 */ 1068 if (ulen == 2) { 1069 (*ilen)--; 1070 (*instr)++; 1071 return (0); 1072 } 1073 1074 /* 1075 * return magic number for ascii char 1076 */ 1077 if ((len - *ilen) == 1) { 1078 c = *(*instr -1); 1079 if (! (c & 0x80)) { 1080 c = unix2dos[c]; 1081 if (c <= 2) 1082 return (c); 1083 } 1084 } 1085 1086 /* 1087 * now convert using libiconv 1088 */ 1089 *instr -= len - *ilen; 1090 *ilen = (int)len; 1091 1092 olen = len = 2; 1093 outp = outbuf; 1094 msdosfs_iconv->convchr_case(pmp->pm_u2d, (const char **)instr, 1095 ilen, &outp, &olen, KICONV_FROM_UPPER); 1096 len -= olen; 1097 wc = 0; 1098 while(len--) 1099 wc |= (*(outp - len - 1) & 0xff) << (len << 3); 1100 return (wc); 1101 } 1102 1103 (*ilen)--; 1104 c = *(*instr)++; 1105 c = l2u[c]; 1106 c = unix2dos[c]; 1107 return ((u_int16_t)c); 1108 } 1109 1110 /* 1111 * Convert Windows char to Local char 1112 */ 1113 static u_int16_t 1114 win2unixchr(u_int16_t wc, struct msdosfsmount *pmp) 1115 { 1116 u_char *inp, *outp, inbuf[3], outbuf[3]; 1117 size_t ilen, olen, len; 1118 1119 if (wc == 0) 1120 return (0); 1121 1122 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1123 inbuf[0] = (u_char)(wc>>8); 1124 inbuf[1] = (u_char)wc; 1125 inbuf[2] = '\0'; 1126 1127 ilen = olen = len = 2; 1128 inp = inbuf; 1129 outp = outbuf; 1130 msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen, 1131 (char **)&outp, &olen); 1132 len -= olen; 1133 1134 /* 1135 * return '?' if failed to convert 1136 */ 1137 if (len == 0) { 1138 wc = '?'; 1139 return (wc); 1140 } 1141 1142 wc = 0; 1143 while(len--) 1144 wc |= (*(outp - len - 1) & 0xff) << (len << 3); 1145 return (wc); 1146 } 1147 1148 if (wc & 0xff00) 1149 wc = '?'; 1150 1151 return (wc); 1152 } 1153 1154 /* 1155 * Convert Local char to Windows char 1156 */ 1157 static u_int16_t 1158 unix2winchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp) 1159 { 1160 u_char *outp, outbuf[3]; 1161 u_int16_t wc; 1162 size_t olen; 1163 1164 if (*ilen == 0) 1165 return (0); 1166 1167 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1168 outp = outbuf; 1169 olen = 2; 1170 if (lower & (LCASE_BASE | LCASE_EXT)) 1171 msdosfs_iconv->convchr_case(pmp->pm_u2w, (const char **)instr, 1172 ilen, (char **)&outp, &olen, 1173 KICONV_FROM_LOWER); 1174 else 1175 msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr, 1176 ilen, (char **)&outp, &olen); 1177 1178 /* 1179 * return '0' if end of filename 1180 */ 1181 if (olen == 2) 1182 return (0); 1183 1184 wc = (outbuf[0]<<8) | outbuf[1]; 1185 1186 return (wc); 1187 } 1188 1189 (*ilen)--; 1190 wc = (*instr)[0]; 1191 if (lower & (LCASE_BASE | LCASE_EXT)) 1192 wc = u2l[wc]; 1193 (*instr)++; 1194 return (wc); 1195 } 1196 1197 /* 1198 * Make subent empty 1199 */ 1200 void 1201 mbnambuf_init(void) 1202 { 1203 int i; 1204 1205 for (i = 0; i < WIN_MAXSUBENTRIES; i++) { 1206 if (subent[i].p) { 1207 free(subent[i].p, M_MSDOSFSMNT); 1208 subent[i].p = NULL; 1209 subent[i].n = 0; 1210 } 1211 } 1212 } 1213 1214 /* 1215 * Write a subent entry from a slot 1216 */ 1217 void 1218 mbnambuf_write(char *name, int id) 1219 { 1220 if (subent[id].p) { 1221 printf("mbnambuf_write(): %s -> %s\n", subent[id].p, name); 1222 free(subent[id].p, M_MSDOSFSMNT); 1223 } 1224 subent[id].n = strlen(name); 1225 subent[id].p = malloc(subent[id].n + 1, M_MSDOSFSMNT, M_WAITOK); 1226 strcpy(subent[id].p, name); 1227 } 1228 1229 /* 1230 * Combine each subents to the *dp and initialize subent 1231 */ 1232 char * 1233 mbnambuf_flush(struct dirent *dp) 1234 { 1235 int i; 1236 char *name = dp->d_name; 1237 1238 *name = '\0'; 1239 dp->d_namlen = 0; 1240 for (i = 0; i < WIN_MAXSUBENTRIES; i++) { 1241 if (subent[i].p) { 1242 if (dp->d_namlen + subent[i].n > sizeof(dp->d_name) - 1) { 1243 mbnambuf_init(); 1244 return (NULL); 1245 } 1246 strcpy(name, subent[i].p); 1247 dp->d_namlen += subent[i].n; 1248 name += subent[i].n; 1249 } 1250 } 1251 mbnambuf_init(); 1252 return (dp->d_name); 1253 } 1254