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 checksum of a DOS filename for Win95 use 913 */ 914 u_int8_t 915 winChksum(name) 916 u_int8_t *name; 917 { 918 int i; 919 u_int8_t s; 920 921 for (s = 0, i = 11; --i >= 0; s += *name++) 922 s = (s << 7)|(s >> 1); 923 return s; 924 } 925 926 /* 927 * Determine the number of slots necessary for Win95 names 928 */ 929 int 930 winSlotCnt(un, unlen, pmp) 931 const u_char *un; 932 size_t unlen; 933 struct msdosfsmount *pmp; 934 { 935 size_t wlen; 936 char wn[WIN_MAXLEN * 2 + 1], *wnp; 937 938 unlen = winLenFixup(un, unlen); 939 940 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 941 wlen = WIN_MAXLEN * 2; 942 wnp = wn; 943 msdosfs_iconv->conv(pmp->pm_u2w, (const char **)&un, &unlen, &wnp, &wlen); 944 if (unlen > 0) 945 return 0; 946 return howmany(WIN_MAXLEN - wlen/2, WIN_CHARS); 947 } 948 949 if (unlen > WIN_MAXLEN) 950 return 0; 951 return howmany(unlen, WIN_CHARS); 952 } 953 954 /* 955 * Determine the number of bytes neccesary for Win95 names 956 */ 957 size_t 958 winLenFixup(un, unlen) 959 const u_char* un; 960 size_t unlen; 961 { 962 for (un += unlen; unlen > 0; unlen--) 963 if (*--un != ' ' && *un != '.') 964 break; 965 return unlen; 966 } 967 968 /* 969 * Store an area with multi byte string instr, and reterns left 970 * byte of instr and moves pointer forward. The area's size is 971 * inlen or outlen. 972 */ 973 static int 974 mbsadjpos(const char **instr, size_t inlen, size_t outlen, int weight, int flag, void *handle) 975 { 976 char *outp, outstr[outlen * weight + 1]; 977 978 if (flag & MSDOSFSMNT_KICONV && msdosfs_iconv) { 979 outp = outstr; 980 outlen *= weight; 981 msdosfs_iconv->conv(handle, instr, &inlen, &outp, &outlen); 982 return (inlen); 983 } 984 985 (*instr) += min(inlen, outlen); 986 return (inlen - min(inlen, outlen)); 987 } 988 989 /* 990 * Convert DOS char to Local char 991 */ 992 static u_int16_t 993 dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp) 994 { 995 u_char c; 996 char *outp, outbuf[3]; 997 u_int16_t wc; 998 size_t len, olen; 999 1000 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1001 olen = len = 2; 1002 outp = outbuf; 1003 1004 if (lower & (LCASE_BASE | LCASE_EXT)) 1005 msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr, 1006 ilen, &outp, &olen, KICONV_LOWER); 1007 else 1008 msdosfs_iconv->convchr(pmp->pm_d2u, (const char **)instr, 1009 ilen, &outp, &olen); 1010 len -= olen; 1011 1012 /* 1013 * return '?' if failed to convert 1014 */ 1015 if (len == 0) { 1016 (*ilen)--; 1017 (*instr)++; 1018 return ('?'); 1019 } 1020 1021 wc = 0; 1022 while(len--) 1023 wc |= (*(outp - len - 1) & 0xff) << (len << 3); 1024 return (wc); 1025 } 1026 1027 (*ilen)--; 1028 c = *(*instr)++; 1029 c = dos2unix[c]; 1030 if (lower & (LCASE_BASE | LCASE_EXT)) 1031 c = u2l[c]; 1032 return ((u_int16_t)c); 1033 } 1034 1035 /* 1036 * Convert Local char to DOS char 1037 */ 1038 static u_int16_t 1039 unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp) 1040 { 1041 u_char c; 1042 char *up, *outp, unicode[3], outbuf[3]; 1043 u_int16_t wc; 1044 size_t len, ulen, olen; 1045 1046 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1047 /* 1048 * to hide an invisible character, using a unicode filter 1049 */ 1050 ulen = 2; 1051 len = *ilen; 1052 up = unicode; 1053 msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr, 1054 ilen, &up, &ulen); 1055 1056 /* 1057 * cannot be converted 1058 */ 1059 if (ulen == 2) { 1060 (*ilen)--; 1061 (*instr)++; 1062 return (0); 1063 } 1064 1065 /* 1066 * return magic number for ascii char 1067 */ 1068 if ((len - *ilen) == 1) { 1069 c = *(*instr -1); 1070 if (! (c & 0x80)) { 1071 c = unix2dos[c]; 1072 if (c <= 2) 1073 return (c); 1074 } 1075 } 1076 1077 /* 1078 * now convert using libiconv 1079 */ 1080 *instr -= len - *ilen; 1081 *ilen = (int)len; 1082 1083 olen = len = 2; 1084 outp = outbuf; 1085 msdosfs_iconv->convchr_case(pmp->pm_u2d, (const char **)instr, 1086 ilen, &outp, &olen, KICONV_FROM_UPPER); 1087 len -= olen; 1088 wc = 0; 1089 while(len--) 1090 wc |= (*(outp - len - 1) & 0xff) << (len << 3); 1091 return (wc); 1092 } 1093 1094 (*ilen)--; 1095 c = *(*instr)++; 1096 c = l2u[c]; 1097 c = unix2dos[c]; 1098 return ((u_int16_t)c); 1099 } 1100 1101 /* 1102 * Convert Windows char to Local char 1103 */ 1104 static u_int16_t 1105 win2unixchr(u_int16_t wc, struct msdosfsmount *pmp) 1106 { 1107 u_char *inp, *outp, inbuf[3], outbuf[3]; 1108 size_t ilen, olen, len; 1109 1110 if (wc == 0) 1111 return (0); 1112 1113 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1114 inbuf[0] = (u_char)(wc>>8); 1115 inbuf[1] = (u_char)wc; 1116 inbuf[2] = '\0'; 1117 1118 ilen = olen = len = 2; 1119 inp = inbuf; 1120 outp = outbuf; 1121 msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen, 1122 (char **)&outp, &olen); 1123 len -= olen; 1124 1125 /* 1126 * return '?' if failed to convert 1127 */ 1128 if (len == 0) { 1129 wc = '?'; 1130 return (wc); 1131 } 1132 1133 wc = 0; 1134 while(len--) 1135 wc |= (*(outp - len - 1) & 0xff) << (len << 3); 1136 return (wc); 1137 } 1138 1139 if (wc & 0xff00) 1140 wc = '?'; 1141 1142 return (wc); 1143 } 1144 1145 /* 1146 * Convert Local char to Windows char 1147 */ 1148 static u_int16_t 1149 unix2winchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp) 1150 { 1151 u_char *outp, outbuf[3]; 1152 u_int16_t wc; 1153 size_t olen; 1154 1155 if (*ilen == 0) 1156 return (0); 1157 1158 if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { 1159 outp = outbuf; 1160 olen = 2; 1161 if (lower & (LCASE_BASE | LCASE_EXT)) 1162 msdosfs_iconv->convchr_case(pmp->pm_u2w, (const char **)instr, 1163 ilen, (char **)&outp, &olen, 1164 KICONV_FROM_LOWER); 1165 else 1166 msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr, 1167 ilen, (char **)&outp, &olen); 1168 1169 /* 1170 * return '0' if end of filename 1171 */ 1172 if (olen == 2) 1173 return (0); 1174 1175 wc = (outbuf[0]<<8) | outbuf[1]; 1176 1177 return (wc); 1178 } 1179 1180 (*ilen)--; 1181 wc = (*instr)[0]; 1182 if (lower & (LCASE_BASE | LCASE_EXT)) 1183 wc = u2l[wc]; 1184 (*instr)++; 1185 return (wc); 1186 } 1187 1188 /* 1189 * Make subent empty 1190 */ 1191 void 1192 mbnambuf_init(void) 1193 { 1194 int i; 1195 1196 for (i = 0; i < WIN_MAXSUBENTRIES; i++) { 1197 if (subent[i].p) { 1198 free(subent[i].p, M_MSDOSFSMNT); 1199 subent[i].p = NULL; 1200 subent[i].n = 0; 1201 } 1202 } 1203 } 1204 1205 /* 1206 * Write a subent entry from a slot 1207 */ 1208 void 1209 mbnambuf_write(char *name, int id) 1210 { 1211 if (subent[id].p) { 1212 printf("mbnambuf_write(): %s -> %s\n", subent[id].p, name); 1213 free(subent[id].p, M_MSDOSFSMNT); 1214 } 1215 subent[id].n = strlen(name); 1216 subent[id].p = malloc(subent[id].n + 1, M_MSDOSFSMNT, M_WAITOK); 1217 strcpy(subent[id].p, name); 1218 } 1219 1220 /* 1221 * Combine each subents to the *dp and initialize subent 1222 */ 1223 char * 1224 mbnambuf_flush(struct dirent *dp) 1225 { 1226 int i; 1227 char *name = dp->d_name; 1228 1229 *name = '\0'; 1230 dp->d_namlen = 0; 1231 for (i = 0; i < WIN_MAXSUBENTRIES; i++) { 1232 if (subent[i].p) { 1233 if (dp->d_namlen + subent[i].n > sizeof(dp->d_name) - 1) { 1234 mbnambuf_init(); 1235 return (NULL); 1236 } 1237 strcpy(name, subent[i].p); 1238 dp->d_namlen += subent[i].n; 1239 name += subent[i].n; 1240 } 1241 } 1242 mbnambuf_init(); 1243 return (dp->d_name); 1244 } 1245