1 |
|
|
/* $OpenBSD: msdosfs_conv.c,v 1.1 2016/10/18 17:05:30 natano Exp $ */ |
2 |
|
|
/* $NetBSD: msdosfs_conv.c,v 1.24 1997/10/17 11:23:54 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/dirent.h> |
57 |
|
|
#include <sys/lock.h> |
58 |
|
|
|
59 |
|
|
/* |
60 |
|
|
* MSDOSFS include files. |
61 |
|
|
*/ |
62 |
|
|
#include "msdos/direntry.h" |
63 |
|
|
#include "msdos/denode.h" |
64 |
|
|
|
65 |
|
|
/* |
66 |
|
|
* Days in each month in a regular year. |
67 |
|
|
*/ |
68 |
|
|
const u_short regyear[] = { |
69 |
|
|
31, 28, 31, 30, 31, 30, |
70 |
|
|
31, 31, 30, 31, 30, 31 |
71 |
|
|
}; |
72 |
|
|
|
73 |
|
|
/* |
74 |
|
|
* Days in each month in a leap year. |
75 |
|
|
*/ |
76 |
|
|
const u_short leapyear[] = { |
77 |
|
|
31, 29, 31, 30, 31, 30, |
78 |
|
|
31, 31, 30, 31, 30, 31 |
79 |
|
|
}; |
80 |
|
|
|
81 |
|
|
/* |
82 |
|
|
* Variables used to remember parts of the last time conversion. Maybe we |
83 |
|
|
* can avoid a full conversion. |
84 |
|
|
*/ |
85 |
|
|
time_t lasttime; |
86 |
|
|
uint32_t lastday; |
87 |
|
|
u_short lastddate; |
88 |
|
|
u_short lastdtime; |
89 |
|
|
|
90 |
|
|
/* |
91 |
|
|
* Convert the unix version of time to dos's idea of time to be used in |
92 |
|
|
* file timestamps. The passed in unix time is assumed to be in GMT. |
93 |
|
|
*/ |
94 |
|
|
void |
95 |
|
|
unix2dostime(struct timespec *tsp, int minuteswest, u_int16_t *ddp, |
96 |
|
|
u_int16_t *dtp, u_int8_t *dhp) |
97 |
|
|
{ |
98 |
|
|
time_t t; |
99 |
|
|
uint32_t days; |
100 |
|
|
uint32_t inc; |
101 |
|
|
uint32_t year; |
102 |
|
|
uint32_t month; |
103 |
|
|
const u_short *months; |
104 |
|
|
|
105 |
|
|
/* |
106 |
|
|
* If the time from the last conversion is the same as now, then |
107 |
|
|
* skip the computations and use the saved result. |
108 |
|
|
*/ |
109 |
|
|
t = tsp->tv_sec - (minuteswest * 60) |
110 |
|
|
/* +- daylight saving time correction */ ; |
111 |
|
|
t &= ~1; |
112 |
|
|
/* |
113 |
|
|
* Before 1/1/1980 there is only a timeless void. After 12/31/2107 |
114 |
|
|
* there is only Cthulhu. |
115 |
|
|
*/ |
116 |
|
|
#define DOSEPOCH 315532800LL |
117 |
|
|
#define DOSENDTIME 4354775999LL |
118 |
|
|
if (t < DOSEPOCH || t > DOSENDTIME) |
119 |
|
|
t = DOSEPOCH; |
120 |
|
|
|
121 |
|
|
if (lasttime != t) { |
122 |
|
|
lasttime = t; |
123 |
|
|
lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT) |
124 |
|
|
+ (((t / 60) % 60) << DT_MINUTES_SHIFT) |
125 |
|
|
+ (((t / 3600) % 24) << DT_HOURS_SHIFT); |
126 |
|
|
|
127 |
|
|
/* |
128 |
|
|
* If the number of days since 1970 is the same as the last |
129 |
|
|
* time we did the computation then skip all this leap year |
130 |
|
|
* and month stuff. |
131 |
|
|
*/ |
132 |
|
|
days = t / (24 * 60 * 60); |
133 |
|
|
if (days != lastday) { |
134 |
|
|
lastday = days; |
135 |
|
|
for (year = 1970;; year++) { |
136 |
|
|
inc = year & 0x03 ? 365 : 366; |
137 |
|
|
if (days < inc) |
138 |
|
|
break; |
139 |
|
|
days -= inc; |
140 |
|
|
} |
141 |
|
|
months = year & 0x03 ? regyear : leapyear; |
142 |
|
|
for (month = 0; month < 12; month++) { |
143 |
|
|
if (days < months[month]) |
144 |
|
|
break; |
145 |
|
|
days -= months[month]; |
146 |
|
|
} |
147 |
|
|
lastddate = ((days + 1) << DD_DAY_SHIFT) |
148 |
|
|
+ ((month + 1) << DD_MONTH_SHIFT); |
149 |
|
|
/* |
150 |
|
|
* Remember dos's idea of time is relative to 1980. |
151 |
|
|
* unix's is relative to 1970. If somehow we get a |
152 |
|
|
* time before 1980 then don't give totally crazy |
153 |
|
|
* results. |
154 |
|
|
*/ |
155 |
|
|
if (year > 1980) |
156 |
|
|
lastddate += (year - 1980) << DD_YEAR_SHIFT; |
157 |
|
|
} |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
if (dtp != NULL) |
161 |
|
|
*dtp = lastdtime; |
162 |
|
|
if (dhp != NULL) |
163 |
|
|
*dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000; |
164 |
|
|
|
165 |
|
|
*ddp = lastddate; |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
static const u_char |
169 |
|
|
unix2dos[256] = { |
170 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */ |
171 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 08-0f */ |
172 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */ |
173 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 18-1f */ |
174 |
|
|
0, 0x21, 0, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */ |
175 |
|
|
0x28, 0x29, 0, 0, 0, 0x2d, 0, 0, /* 28-2f */ |
176 |
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */ |
177 |
|
|
0x38, 0x39, 0, 0, 0, 0, 0, 0, /* 38-3f */ |
178 |
|
|
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */ |
179 |
|
|
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */ |
180 |
|
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */ |
181 |
|
|
0x58, 0x59, 0x5a, 0, 0, 0, 0x5e, 0x5f, /* 58-5f */ |
182 |
|
|
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 60-67 */ |
183 |
|
|
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 68-6f */ |
184 |
|
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 70-77 */ |
185 |
|
|
0x58, 0x59, 0x5a, 0x7b, 0, 0x7d, 0x7e, 0, /* 78-7f */ |
186 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 80-87 */ |
187 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 88-8f */ |
188 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 90-97 */ |
189 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 98-9f */ |
190 |
|
|
0, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */ |
191 |
|
|
0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */ |
192 |
|
|
0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */ |
193 |
|
|
0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */ |
194 |
|
|
0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */ |
195 |
|
|
0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */ |
196 |
|
|
0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */ |
197 |
|
|
0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */ |
198 |
|
|
0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */ |
199 |
|
|
0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */ |
200 |
|
|
0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */ |
201 |
|
|
0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */ |
202 |
|
|
}; |
203 |
|
|
|
204 |
|
|
static const u_char |
205 |
|
|
u2l[256] = { |
206 |
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */ |
207 |
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */ |
208 |
|
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */ |
209 |
|
|
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */ |
210 |
|
|
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */ |
211 |
|
|
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */ |
212 |
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */ |
213 |
|
|
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */ |
214 |
|
|
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 40-47 */ |
215 |
|
|
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 48-4f */ |
216 |
|
|
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 50-57 */ |
217 |
|
|
0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */ |
218 |
|
|
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */ |
219 |
|
|
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */ |
220 |
|
|
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */ |
221 |
|
|
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */ |
222 |
|
|
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */ |
223 |
|
|
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */ |
224 |
|
|
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */ |
225 |
|
|
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */ |
226 |
|
|
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */ |
227 |
|
|
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */ |
228 |
|
|
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */ |
229 |
|
|
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */ |
230 |
|
|
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */ |
231 |
|
|
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */ |
232 |
|
|
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */ |
233 |
|
|
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */ |
234 |
|
|
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */ |
235 |
|
|
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */ |
236 |
|
|
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */ |
237 |
|
|
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */ |
238 |
|
|
}; |
239 |
|
|
|
240 |
|
|
/* |
241 |
|
|
* DOS filenames are made of 2 parts, the name part and the extension part. |
242 |
|
|
* The name part is 8 characters long and the extension part is 3 |
243 |
|
|
* characters long. They may contain trailing blanks if the name or |
244 |
|
|
* extension are not long enough to fill their respective fields. |
245 |
|
|
*/ |
246 |
|
|
|
247 |
|
|
/* |
248 |
|
|
* Convert a unix filename to a DOS filename according to Win95 rules. |
249 |
|
|
* If applicable and gen is not 0, it is inserted into the converted |
250 |
|
|
* filename as a generation number. |
251 |
|
|
* Returns |
252 |
|
|
* 0 if name couldn't be converted |
253 |
|
|
* 1 if the converted name is the same as the original |
254 |
|
|
* (no long filename entry necessary for Win95) |
255 |
|
|
* 2 if conversion was successful |
256 |
|
|
* 3 if conversion was successful and generation number was inserted |
257 |
|
|
*/ |
258 |
|
|
int |
259 |
|
|
unix2dosfn(u_char *un, u_char dn[11], int unlen, u_int gen) |
260 |
|
|
{ |
261 |
|
|
int i, j, l; |
262 |
|
|
int conv = 1; |
263 |
|
|
u_char *cp, *dp, *dp1; |
264 |
|
|
u_char gentext[6]; |
265 |
|
|
|
266 |
|
|
/* |
267 |
|
|
* Fill the dos filename string with blanks. These are DOS's pad |
268 |
|
|
* characters. |
269 |
|
|
*/ |
270 |
|
|
for (i = 0; i < 11; i++) |
271 |
|
|
dn[i] = ' '; |
272 |
|
|
|
273 |
|
|
/* |
274 |
|
|
* The filenames "." and ".." are handled specially, since they |
275 |
|
|
* don't follow dos filename rules. |
276 |
|
|
*/ |
277 |
|
|
if (un[0] == '.' && unlen == 1) { |
278 |
|
|
dn[0] = '.'; |
279 |
|
|
return gen <= 1; |
280 |
|
|
} |
281 |
|
|
if (un[0] == '.' && un[1] == '.' && unlen == 2) { |
282 |
|
|
dn[0] = '.'; |
283 |
|
|
dn[1] = '.'; |
284 |
|
|
return gen <= 1; |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
/* |
288 |
|
|
* Filenames with only blanks and dots are not allowed! |
289 |
|
|
*/ |
290 |
|
|
for (cp = un, i = unlen; --i >= 0; cp++) |
291 |
|
|
if (*cp != ' ' && *cp != '.') |
292 |
|
|
break; |
293 |
|
|
if (i < 0) |
294 |
|
|
return 0; |
295 |
|
|
|
296 |
|
|
/* |
297 |
|
|
* Now find the extension |
298 |
|
|
* Note: dot as first char doesn't start extension |
299 |
|
|
* and trailing dots and blanks are ignored |
300 |
|
|
*/ |
301 |
|
|
dp = dp1 = 0; |
302 |
|
|
for (cp = un + 1, i = unlen - 1; --i >= 0;) { |
303 |
|
|
switch (*cp++) { |
304 |
|
|
case '.': |
305 |
|
|
if (!dp1) |
306 |
|
|
dp1 = cp; |
307 |
|
|
break; |
308 |
|
|
case ' ': |
309 |
|
|
break; |
310 |
|
|
default: |
311 |
|
|
if (dp1) |
312 |
|
|
dp = dp1; |
313 |
|
|
dp1 = 0; |
314 |
|
|
break; |
315 |
|
|
} |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
/* |
319 |
|
|
* Now convert it |
320 |
|
|
*/ |
321 |
|
|
if (dp) { |
322 |
|
|
if (dp1) |
323 |
|
|
l = dp1 - dp; |
324 |
|
|
else |
325 |
|
|
l = unlen - (dp - un); |
326 |
|
|
for (i = 0, j = 8; i < l && j < 11; i++, j++) { |
327 |
|
|
if (dp[i] != (dn[j] = unix2dos[dp[i]]) |
328 |
|
|
&& conv != 3) |
329 |
|
|
conv = 2; |
330 |
|
|
if (!dn[j]) { |
331 |
|
|
conv = 3; |
332 |
|
|
dn[j--] = ' '; |
333 |
|
|
} |
334 |
|
|
} |
335 |
|
|
if (i < l) |
336 |
|
|
conv = 3; |
337 |
|
|
dp--; |
338 |
|
|
} else { |
339 |
|
|
for (dp = cp; *--dp == ' ' || *dp == '.';); |
340 |
|
|
dp++; |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
/* |
344 |
|
|
* Now convert the rest of the name |
345 |
|
|
*/ |
346 |
|
|
for (i = j = 0; un < dp && j < 8; i++, j++, un++) { |
347 |
|
|
if (*un != (dn[j] = unix2dos[*un]) |
348 |
|
|
&& conv != 3) |
349 |
|
|
conv = 2; |
350 |
|
|
if (!dn[j]) { |
351 |
|
|
conv = 3; |
352 |
|
|
dn[j--] = ' '; |
353 |
|
|
} |
354 |
|
|
} |
355 |
|
|
if (un < dp) |
356 |
|
|
conv = 3; |
357 |
|
|
/* |
358 |
|
|
* If we didn't have any chars in filename, |
359 |
|
|
* generate a default |
360 |
|
|
*/ |
361 |
|
|
if (!j) |
362 |
|
|
dn[0] = '_'; |
363 |
|
|
|
364 |
|
|
/* |
365 |
|
|
* The first character cannot be E5, |
366 |
|
|
* because that means a deleted entry |
367 |
|
|
*/ |
368 |
|
|
if (dn[0] == 0xe5) |
369 |
|
|
dn[0] = SLOT_E5; |
370 |
|
|
|
371 |
|
|
/* |
372 |
|
|
* If there wasn't any char dropped, |
373 |
|
|
* there is no place for generation numbers |
374 |
|
|
*/ |
375 |
|
|
if (conv != 3) { |
376 |
|
|
if (gen > 1) |
377 |
|
|
return 0; |
378 |
|
|
return conv; |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
/* |
382 |
|
|
* Now insert the generation number into the filename part |
383 |
|
|
*/ |
384 |
|
|
for (cp = gentext + sizeof(gentext); cp > gentext && gen; gen /= 10) |
385 |
|
|
*--cp = gen % 10 + '0'; |
386 |
|
|
if (gen) |
387 |
|
|
return 0; |
388 |
|
|
for (i = 8; dn[--i] == ' ';); |
389 |
|
|
if (gentext + sizeof(gentext) - cp + 1 > 8 - i) |
390 |
|
|
i = 8 - (gentext + sizeof(gentext) - cp + 1); |
391 |
|
|
dn[i++] = '~'; |
392 |
|
|
while (cp < gentext + sizeof(gentext)) |
393 |
|
|
dn[i++] = *cp++; |
394 |
|
|
return 3; |
395 |
|
|
} |
396 |
|
|
|
397 |
|
|
/* |
398 |
|
|
* Create a Win95 long name directory entry |
399 |
|
|
* Note: assumes that the filename is valid, |
400 |
|
|
* i.e. doesn't consist solely of blanks and dots |
401 |
|
|
*/ |
402 |
|
|
int |
403 |
|
|
unix2winfn(u_char *un, int unlen, struct winentry *wep, int cnt, int chksum) |
404 |
|
|
{ |
405 |
|
|
u_int8_t *cp; |
406 |
|
|
int i; |
407 |
|
|
|
408 |
|
|
/* |
409 |
|
|
* Drop trailing blanks and dots |
410 |
|
|
*/ |
411 |
|
|
for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--); |
412 |
|
|
|
413 |
|
|
un += (cnt - 1) * WIN_CHARS; |
414 |
|
|
unlen -= (cnt - 1) * WIN_CHARS; |
415 |
|
|
|
416 |
|
|
/* |
417 |
|
|
* Initialize winentry to some useful default |
418 |
|
|
*/ |
419 |
|
|
for (cp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *cp++ = 0xff); |
420 |
|
|
wep->weCnt = cnt; |
421 |
|
|
wep->weAttributes = ATTR_WIN95; |
422 |
|
|
wep->weReserved1 = 0; |
423 |
|
|
wep->weChksum = chksum; |
424 |
|
|
wep->weReserved2 = 0; |
425 |
|
|
|
426 |
|
|
/* |
427 |
|
|
* Now convert the filename parts |
428 |
|
|
*/ |
429 |
|
|
for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) { |
430 |
|
|
if (--unlen < 0) |
431 |
|
|
goto done; |
432 |
|
|
*cp++ = *un++; |
433 |
|
|
*cp++ = 0; |
434 |
|
|
} |
435 |
|
|
for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) { |
436 |
|
|
if (--unlen < 0) |
437 |
|
|
goto done; |
438 |
|
|
*cp++ = *un++; |
439 |
|
|
*cp++ = 0; |
440 |
|
|
} |
441 |
|
|
for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) { |
442 |
|
|
if (--unlen < 0) |
443 |
|
|
goto done; |
444 |
|
|
*cp++ = *un++; |
445 |
|
|
*cp++ = 0; |
446 |
|
|
} |
447 |
|
|
if (!unlen) |
448 |
|
|
wep->weCnt |= WIN_LAST; |
449 |
|
|
return unlen; |
450 |
|
|
|
451 |
|
|
done: |
452 |
|
|
*cp++ = 0; |
453 |
|
|
*cp++ = 0; |
454 |
|
|
wep->weCnt |= WIN_LAST; |
455 |
|
|
return 0; |
456 |
|
|
} |
457 |
|
|
|
458 |
|
|
/* |
459 |
|
|
* Compare our filename to the one in the Win95 entry |
460 |
|
|
* Returns the checksum or -1 if no match |
461 |
|
|
*/ |
462 |
|
|
int |
463 |
|
|
winChkName(u_char *un, int unlen, struct winentry *wep, int chksum) |
464 |
|
|
{ |
465 |
|
|
u_int8_t *cp; |
466 |
|
|
int i; |
467 |
|
|
|
468 |
|
|
/* |
469 |
|
|
* First compare checksums |
470 |
|
|
*/ |
471 |
|
|
if (wep->weCnt&WIN_LAST) |
472 |
|
|
chksum = wep->weChksum; |
473 |
|
|
else if (chksum != wep->weChksum) |
474 |
|
|
chksum = -1; |
475 |
|
|
if (chksum == -1) |
476 |
|
|
return -1; |
477 |
|
|
|
478 |
|
|
/* |
479 |
|
|
* Offset of this entry |
480 |
|
|
*/ |
481 |
|
|
i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS; |
482 |
|
|
if ((unlen -= i) <= 0) |
483 |
|
|
return -1; |
484 |
|
|
un += i; |
485 |
|
|
|
486 |
|
|
if ((wep->weCnt&WIN_LAST) && unlen > WIN_CHARS) |
487 |
|
|
return -1; |
488 |
|
|
|
489 |
|
|
/* |
490 |
|
|
* Compare the name parts |
491 |
|
|
*/ |
492 |
|
|
for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) { |
493 |
|
|
if (--unlen < 0) { |
494 |
|
|
if (!*cp++ && !*cp) |
495 |
|
|
return chksum; |
496 |
|
|
return -1; |
497 |
|
|
} |
498 |
|
|
if (u2l[*cp++] != u2l[*un++] || *cp++) |
499 |
|
|
return -1; |
500 |
|
|
} |
501 |
|
|
for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) { |
502 |
|
|
if (--unlen < 0) { |
503 |
|
|
if (!*cp++ && !*cp) |
504 |
|
|
return chksum; |
505 |
|
|
return -1; |
506 |
|
|
} |
507 |
|
|
if (u2l[*cp++] != u2l[*un++] || *cp++) |
508 |
|
|
return -1; |
509 |
|
|
} |
510 |
|
|
for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) { |
511 |
|
|
if (--unlen < 0) { |
512 |
|
|
if (!*cp++ && !*cp) |
513 |
|
|
return chksum; |
514 |
|
|
return -1; |
515 |
|
|
} |
516 |
|
|
if (u2l[*cp++] != u2l[*un++] || *cp++) |
517 |
|
|
return -1; |
518 |
|
|
} |
519 |
|
|
return chksum; |
520 |
|
|
} |
521 |
|
|
|
522 |
|
|
/* |
523 |
|
|
* Compute the checksum of a DOS filename for Win95 use |
524 |
|
|
*/ |
525 |
|
|
u_int8_t |
526 |
|
|
winChksum(u_int8_t *name) |
527 |
|
|
{ |
528 |
|
|
int i; |
529 |
|
|
u_int8_t s; |
530 |
|
|
|
531 |
|
|
for (s = 0, i = 11; --i >= 0; s += *name++) |
532 |
|
|
s = (s << 7)|(s >> 1); |
533 |
|
|
return s; |
534 |
|
|
} |
535 |
|
|
|
536 |
|
|
/* |
537 |
|
|
* Determine the number of slots necessary for Win95 names |
538 |
|
|
*/ |
539 |
|
|
int |
540 |
|
|
winSlotCnt(u_char *un, int unlen) |
541 |
|
|
{ |
542 |
|
|
for (un += unlen; unlen > 0; unlen--) |
543 |
|
|
if (*--un != ' ' && *un != '.') |
544 |
|
|
break; |
545 |
|
|
if (unlen > WIN_MAXLEN) |
546 |
|
|
return 0; |
547 |
|
|
return howmany(unlen, WIN_CHARS); |
548 |
|
|
} |