89e8c9b22ee5bc8077c87ab6d9d4f851e2f58087
[openafs.git] / src / WINNT / afsd / cm_utils.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <errno.h>
14 #include <windows.h>
15 #include <winsock2.h>
16 #ifndef EWOULDBLOCK
17 #define EWOULDBLOCK             WSAEWOULDBLOCK
18 #define EINPROGRESS             WSAEINPROGRESS
19 #define EALREADY                WSAEALREADY
20 #define ENOTSOCK                WSAENOTSOCK
21 #define EDESTADDRREQ            WSAEDESTADDRREQ
22 #define EMSGSIZE                WSAEMSGSIZE
23 #define EPROTOTYPE              WSAEPROTOTYPE
24 #define ENOPROTOOPT             WSAENOPROTOOPT
25 #define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
26 #define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
27 #define EOPNOTSUPP              WSAEOPNOTSUPP
28 #define EPFNOSUPPORT            WSAEPFNOSUPPORT
29 #define EAFNOSUPPORT            WSAEAFNOSUPPORT
30 #define EADDRINUSE              WSAEADDRINUSE
31 #define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
32 #define ENETDOWN                WSAENETDOWN
33 #define ENETUNREACH             WSAENETUNREACH
34 #define ENETRESET               WSAENETRESET
35 #define ECONNABORTED            WSAECONNABORTED
36 #define ECONNRESET              WSAECONNRESET
37 #define ENOBUFS                 WSAENOBUFS
38 #define EISCONN                 WSAEISCONN
39 #define ENOTCONN                WSAENOTCONN
40 #define ESHUTDOWN               WSAESHUTDOWN
41 #define ETOOMANYREFS            WSAETOOMANYREFS
42 #define ETIMEDOUT               WSAETIMEDOUT
43 #define ECONNREFUSED            WSAECONNREFUSED
44 #ifdef ELOOP
45 #undef ELOOP
46 #endif
47 #define ELOOP                   WSAELOOP
48 #ifdef ENAMETOOLONG
49 #undef ENAMETOOLONG
50 #endif
51 #define ENAMETOOLONG            WSAENAMETOOLONG
52 #define EHOSTDOWN               WSAEHOSTDOWN
53 #define EHOSTUNREACH            WSAEHOSTUNREACH
54 #ifdef ENOTEMPTY
55 #undef ENOTEMPTY
56 #endif 
57 #define ENOTEMPTY               WSAENOTEMPTY
58 #define EPROCLIM                WSAEPROCLIM
59 #define EUSERS                  WSAEUSERS
60 #define EDQUOT                  WSAEDQUOT
61 #define ESTALE                  WSAESTALE
62 #define EREMOTE                 WSAEREMOTE
63 #endif /* EWOULDBLOCK */
64 #include <afs/unified_afs.h>
65
66 #include <string.h>
67 #include <malloc.h>
68 #include "afsd.h"
69 #include <osi.h>
70 #include <rx/rx.h>
71
72 #define STRSAFE_NO_DEPRECATE
73 #include <strsafe.h>
74
75
76 static osi_once_t cm_utilsOnce;
77
78 osi_rwlock_t cm_utilsLock;
79
80 cm_space_t *cm_spaceListp;
81
82 static int et2sys[512];
83
84 void
85 init_et_to_sys_error(void)
86 {
87     memset(&et2sys, 0, sizeof(et2sys));
88     et2sys[(UAEPERM - ERROR_TABLE_BASE_uae)] = EPERM;
89     et2sys[(UAENOENT - ERROR_TABLE_BASE_uae)] = ENOENT;
90     et2sys[(UAESRCH - ERROR_TABLE_BASE_uae)] = ESRCH;
91     et2sys[(UAEINTR - ERROR_TABLE_BASE_uae)] = EINTR;
92     et2sys[(UAEIO - ERROR_TABLE_BASE_uae)] = EIO;
93     et2sys[(UAENXIO - ERROR_TABLE_BASE_uae)] = ENXIO;
94     et2sys[(UAE2BIG - ERROR_TABLE_BASE_uae)] = E2BIG;
95     et2sys[(UAENOEXEC - ERROR_TABLE_BASE_uae)] = ENOEXEC;
96     et2sys[(UAEBADF - ERROR_TABLE_BASE_uae)] = EBADF;
97     et2sys[(UAECHILD - ERROR_TABLE_BASE_uae)] = ECHILD;
98     et2sys[(UAEAGAIN - ERROR_TABLE_BASE_uae)] = EAGAIN;
99     et2sys[(UAENOMEM - ERROR_TABLE_BASE_uae)] = ENOMEM;
100     et2sys[(UAEACCES - ERROR_TABLE_BASE_uae)] = EACCES;
101     et2sys[(UAEFAULT - ERROR_TABLE_BASE_uae)] = EFAULT;
102     et2sys[(UAENOTBLK - ERROR_TABLE_BASE_uae)] = ENOTBLK;
103     et2sys[(UAEBUSY - ERROR_TABLE_BASE_uae)] = EBUSY;
104     et2sys[(UAEEXIST - ERROR_TABLE_BASE_uae)] = EEXIST;
105     et2sys[(UAEXDEV - ERROR_TABLE_BASE_uae)] = EXDEV;
106     et2sys[(UAENODEV - ERROR_TABLE_BASE_uae)] = ENODEV;
107     et2sys[(UAENOTDIR - ERROR_TABLE_BASE_uae)] = ENOTDIR;
108     et2sys[(UAEISDIR - ERROR_TABLE_BASE_uae)] = EISDIR;
109     et2sys[(UAEINVAL - ERROR_TABLE_BASE_uae)] = EINVAL;
110     et2sys[(UAENFILE - ERROR_TABLE_BASE_uae)] = ENFILE;
111     et2sys[(UAEMFILE - ERROR_TABLE_BASE_uae)] = EMFILE;
112     et2sys[(UAENOTTY - ERROR_TABLE_BASE_uae)] = ENOTTY;
113     et2sys[(UAETXTBSY - ERROR_TABLE_BASE_uae)] = ETXTBSY;
114     et2sys[(UAEFBIG - ERROR_TABLE_BASE_uae)] = EFBIG;
115     et2sys[(UAENOSPC - ERROR_TABLE_BASE_uae)] = ENOSPC;
116     et2sys[(UAESPIPE - ERROR_TABLE_BASE_uae)] = ESPIPE;
117     et2sys[(UAEROFS - ERROR_TABLE_BASE_uae)] = EROFS;
118     et2sys[(UAEMLINK - ERROR_TABLE_BASE_uae)] = EMLINK;
119     et2sys[(UAEPIPE - ERROR_TABLE_BASE_uae)] = EPIPE;
120     et2sys[(UAEDOM - ERROR_TABLE_BASE_uae)] = EDOM;
121     et2sys[(UAERANGE - ERROR_TABLE_BASE_uae)] = ERANGE;
122     et2sys[(UAEDEADLK - ERROR_TABLE_BASE_uae)] = EDEADLK;
123     et2sys[(UAENAMETOOLONG - ERROR_TABLE_BASE_uae)] = ENAMETOOLONG;
124     et2sys[(UAENOLCK - ERROR_TABLE_BASE_uae)] = ENOLCK;
125     et2sys[(UAENOSYS - ERROR_TABLE_BASE_uae)] = ENOSYS;
126     et2sys[(UAENOTEMPTY - ERROR_TABLE_BASE_uae)] = ENOTEMPTY;
127     et2sys[(UAELOOP - ERROR_TABLE_BASE_uae)] = ELOOP;
128     et2sys[(UAEWOULDBLOCK - ERROR_TABLE_BASE_uae)] = EWOULDBLOCK;
129     et2sys[(UAENOMSG - ERROR_TABLE_BASE_uae)] = ENOMSG;
130     et2sys[(UAEIDRM - ERROR_TABLE_BASE_uae)] = EIDRM;
131     et2sys[(UAECHRNG - ERROR_TABLE_BASE_uae)] = ECHRNG;
132     et2sys[(UAEL2NSYNC - ERROR_TABLE_BASE_uae)] = EL2NSYNC;
133     et2sys[(UAEL3HLT - ERROR_TABLE_BASE_uae)] = EL3HLT;
134     et2sys[(UAEL3RST - ERROR_TABLE_BASE_uae)] = EL3RST;
135     et2sys[(UAELNRNG - ERROR_TABLE_BASE_uae)] = ELNRNG;
136     et2sys[(UAEUNATCH - ERROR_TABLE_BASE_uae)] = EUNATCH;
137     et2sys[(UAENOCSI - ERROR_TABLE_BASE_uae)] = ENOCSI;
138     et2sys[(UAEL2HLT - ERROR_TABLE_BASE_uae)] = EL2HLT;
139     et2sys[(UAEBADE - ERROR_TABLE_BASE_uae)] = EBADE;
140     et2sys[(UAEBADR - ERROR_TABLE_BASE_uae)] = EBADR;
141     et2sys[(UAEXFULL - ERROR_TABLE_BASE_uae)] = EXFULL;
142     et2sys[(UAENOANO - ERROR_TABLE_BASE_uae)] = ENOANO;
143     et2sys[(UAEBADRQC - ERROR_TABLE_BASE_uae)] = EBADRQC;
144     et2sys[(UAEBADSLT - ERROR_TABLE_BASE_uae)] = EBADSLT;
145     et2sys[(UAEBFONT - ERROR_TABLE_BASE_uae)] = EBFONT;
146     et2sys[(UAENOSTR - ERROR_TABLE_BASE_uae)] = ENOSTR;
147     et2sys[(UAENODATA - ERROR_TABLE_BASE_uae)] = ENODATA;
148     et2sys[(UAETIME - ERROR_TABLE_BASE_uae)] = ETIME;
149     et2sys[(UAENOSR - ERROR_TABLE_BASE_uae)] = ENOSR;
150     et2sys[(UAENONET - ERROR_TABLE_BASE_uae)] = ENONET;
151     et2sys[(UAENOPKG - ERROR_TABLE_BASE_uae)] = ENOPKG;
152     et2sys[(UAEREMOTE - ERROR_TABLE_BASE_uae)] = EREMOTE;
153     et2sys[(UAENOLINK - ERROR_TABLE_BASE_uae)] = ENOLINK;
154     et2sys[(UAEADV - ERROR_TABLE_BASE_uae)] = EADV;
155     et2sys[(UAESRMNT - ERROR_TABLE_BASE_uae)] = ESRMNT;
156     et2sys[(UAECOMM - ERROR_TABLE_BASE_uae)] = ECOMM;
157     et2sys[(UAEPROTO - ERROR_TABLE_BASE_uae)] = EPROTO;
158     et2sys[(UAEMULTIHOP - ERROR_TABLE_BASE_uae)] = EMULTIHOP;
159     et2sys[(UAEDOTDOT - ERROR_TABLE_BASE_uae)] = EDOTDOT;
160     et2sys[(UAEBADMSG - ERROR_TABLE_BASE_uae)] = EBADMSG;
161     et2sys[(UAEOVERFLOW - ERROR_TABLE_BASE_uae)] = EOVERFLOW;
162     et2sys[(UAENOTUNIQ - ERROR_TABLE_BASE_uae)] = ENOTUNIQ;
163     et2sys[(UAEBADFD - ERROR_TABLE_BASE_uae)] = EBADFD;
164     et2sys[(UAEREMCHG - ERROR_TABLE_BASE_uae)] = EREMCHG;
165     et2sys[(UAELIBACC - ERROR_TABLE_BASE_uae)] = ELIBACC;
166     et2sys[(UAELIBBAD - ERROR_TABLE_BASE_uae)] = ELIBBAD;
167     et2sys[(UAELIBSCN - ERROR_TABLE_BASE_uae)] = ELIBSCN;
168     et2sys[(UAELIBMAX - ERROR_TABLE_BASE_uae)] = ELIBMAX;
169     et2sys[(UAELIBEXEC - ERROR_TABLE_BASE_uae)] = ELIBEXEC;
170     et2sys[(UAEILSEQ - ERROR_TABLE_BASE_uae)] = EILSEQ;
171     et2sys[(UAERESTART - ERROR_TABLE_BASE_uae)] = ERESTART;
172     et2sys[(UAESTRPIPE - ERROR_TABLE_BASE_uae)] = ESTRPIPE;
173     et2sys[(UAEUSERS - ERROR_TABLE_BASE_uae)] = EUSERS;
174     et2sys[(UAENOTSOCK - ERROR_TABLE_BASE_uae)] = ENOTSOCK;
175     et2sys[(UAEDESTADDRREQ - ERROR_TABLE_BASE_uae)] = EDESTADDRREQ;
176     et2sys[(UAEMSGSIZE - ERROR_TABLE_BASE_uae)] = EMSGSIZE;
177     et2sys[(UAEPROTOTYPE - ERROR_TABLE_BASE_uae)] = EPROTOTYPE;
178     et2sys[(UAENOPROTOOPT - ERROR_TABLE_BASE_uae)] = ENOPROTOOPT;
179     et2sys[(UAEPROTONOSUPPORT - ERROR_TABLE_BASE_uae)] = EPROTONOSUPPORT;
180     et2sys[(UAESOCKTNOSUPPORT - ERROR_TABLE_BASE_uae)] = ESOCKTNOSUPPORT;
181     et2sys[(UAEOPNOTSUPP - ERROR_TABLE_BASE_uae)] = EOPNOTSUPP;
182     et2sys[(UAEPFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EPFNOSUPPORT;
183     et2sys[(UAEAFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EAFNOSUPPORT;
184     et2sys[(UAEADDRINUSE - ERROR_TABLE_BASE_uae)] = EADDRINUSE;
185     et2sys[(UAEADDRNOTAVAIL - ERROR_TABLE_BASE_uae)] = EADDRNOTAVAIL;
186     et2sys[(UAENETDOWN - ERROR_TABLE_BASE_uae)] = ENETDOWN;
187     et2sys[(UAENETUNREACH - ERROR_TABLE_BASE_uae)] = ENETUNREACH;
188     et2sys[(UAENETRESET - ERROR_TABLE_BASE_uae)] = ENETRESET;
189     et2sys[(UAECONNABORTED - ERROR_TABLE_BASE_uae)] = ECONNABORTED;
190     et2sys[(UAECONNRESET - ERROR_TABLE_BASE_uae)] = ECONNRESET;
191     et2sys[(UAENOBUFS - ERROR_TABLE_BASE_uae)] = ENOBUFS;
192     et2sys[(UAEISCONN - ERROR_TABLE_BASE_uae)] = EISCONN;
193     et2sys[(UAENOTCONN - ERROR_TABLE_BASE_uae)] = ENOTCONN;
194     et2sys[(UAESHUTDOWN - ERROR_TABLE_BASE_uae)] = ESHUTDOWN;
195     et2sys[(UAETOOMANYREFS - ERROR_TABLE_BASE_uae)] = ETOOMANYREFS;
196     et2sys[(UAETIMEDOUT - ERROR_TABLE_BASE_uae)] = ETIMEDOUT;
197     et2sys[(UAECONNREFUSED - ERROR_TABLE_BASE_uae)] = ECONNREFUSED;
198     et2sys[(UAEHOSTDOWN - ERROR_TABLE_BASE_uae)] = EHOSTDOWN;
199     et2sys[(UAEHOSTUNREACH - ERROR_TABLE_BASE_uae)] = EHOSTUNREACH;
200     et2sys[(UAEALREADY - ERROR_TABLE_BASE_uae)] = EALREADY;
201     et2sys[(UAEINPROGRESS - ERROR_TABLE_BASE_uae)] = EINPROGRESS;
202     et2sys[(UAESTALE - ERROR_TABLE_BASE_uae)] = ESTALE;
203     et2sys[(UAEUCLEAN - ERROR_TABLE_BASE_uae)] = EUCLEAN;
204     et2sys[(UAENOTNAM - ERROR_TABLE_BASE_uae)] = ENOTNAM;
205     et2sys[(UAENAVAIL - ERROR_TABLE_BASE_uae)] = ENAVAIL;
206     et2sys[(UAEISNAM - ERROR_TABLE_BASE_uae)] = EISNAM;
207     et2sys[(UAEREMOTEIO - ERROR_TABLE_BASE_uae)] = EREMOTEIO;
208     et2sys[(UAEDQUOT - ERROR_TABLE_BASE_uae)] = EDQUOT;
209     et2sys[(UAENOMEDIUM - ERROR_TABLE_BASE_uae)] = ENOMEDIUM;
210     et2sys[(UAEMEDIUMTYPE - ERROR_TABLE_BASE_uae)] = EMEDIUMTYPE;
211 }
212
213 static afs_int32
214 et_to_sys_error(afs_int32 in)
215 {
216     if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512)
217         return in;
218     if (et2sys[in - ERROR_TABLE_BASE_uae] != 0)
219         return et2sys[in - ERROR_TABLE_BASE_uae];
220     return in;
221 }
222
223 long cm_MapRPCError(long error, cm_req_t *reqp)
224 {
225     if (error == 0) 
226         return 0;
227
228     /* If we had to stop retrying, report our saved error code. */
229     if (reqp && error == CM_ERROR_TIMEDOUT) {
230         if (reqp->accessError)
231             return reqp->accessError;
232         if (reqp->volumeError)
233             return reqp->volumeError;
234         if (reqp->rpcError)
235             return reqp->rpcError;
236         return error;
237     }
238
239     error = et_to_sys_error(error);
240
241     if (error < 0) 
242         error = CM_ERROR_TIMEDOUT;
243     else if (error == EROFS) 
244         error = CM_ERROR_READONLY;
245     else if (error == EACCES) 
246         error = CM_ERROR_NOACCESS;
247     else if (error == EXDEV) 
248         error = CM_ERROR_CROSSDEVLINK;
249     else if (error == EEXIST) 
250         error = CM_ERROR_EXISTS;
251     else if (error == ENOTDIR) 
252         error = CM_ERROR_NOTDIR;
253     else if (error == ENOENT)
254         error = CM_ERROR_NOSUCHFILE;
255     else if (error == EAGAIN
256              || error == 35        /* EAGAIN, Digital UNIX */
257              || error == WSAEWOULDBLOCK)
258         error = CM_ERROR_WOULDBLOCK;
259     else if (error == VDISKFULL
260               || error == ENOSPC)
261         error = CM_ERROR_SPACE;
262     else if (error == VOVERQUOTA
263               || error == EDQUOT
264               || error == 49    /* EDQUOT on Solaris */
265               || error == 88    /* EDQUOT on AIX */
266               || error == 69    /* EDQUOT on Digital UNIX and HPUX */
267               || error == 122   /* EDQUOT on Linux */
268               || error == 1133) /* EDQUOT on Irix  */
269         error = CM_ERROR_QUOTA;
270     else if (error == VNOVNODE)
271         error = CM_ERROR_BADFD;
272     else if (error == EISDIR)
273         return CM_ERROR_ISDIR;
274     return error;
275 }
276
277 long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
278 {
279     if (error == 0) 
280         return 0;
281
282     /* If we had to stop retrying, report our saved error code. */
283     if (reqp && error == CM_ERROR_TIMEDOUT) {
284         if (reqp->accessError)
285             return reqp->accessError;
286         if (reqp->volumeError)
287             return reqp->volumeError;
288         if (reqp->rpcError)
289             return reqp->rpcError;
290         return error;
291     }
292
293     error = et_to_sys_error(error);
294
295     if (error < 0) 
296         error = CM_ERROR_TIMEDOUT;
297     else if (error == EROFS) 
298         error = CM_ERROR_READONLY;
299     else if (error == ENOTDIR) 
300         error = CM_ERROR_NOTDIR;
301     else if (error == EACCES) 
302         error = CM_ERROR_NOACCESS;
303     else if (error == ENOENT) 
304         error = CM_ERROR_NOSUCHFILE;
305     else if (error == ENOTEMPTY 
306               || error == 17            /* AIX */
307               || error == 66            /* SunOS 4, Digital UNIX */
308               || error == 93            /* Solaris 2, IRIX */
309               || error == 247)  /* HP/UX */
310         error = CM_ERROR_NOTEMPTY;
311     return error;
312 }       
313
314 long cm_MapVLRPCError(long error, cm_req_t *reqp)
315 {
316     if (error == 0) return 0;
317
318     /* If we had to stop retrying, report our saved error code. */
319     if (reqp && error == CM_ERROR_TIMEDOUT) {
320         if (reqp->accessError)
321             return reqp->accessError;
322         if (reqp->volumeError)
323             return reqp->volumeError;
324         if (reqp->rpcError)
325             return reqp->rpcError;
326         return error;
327     }
328
329     error = et_to_sys_error(error);
330
331     if (error < 0) 
332         error = CM_ERROR_TIMEDOUT;
333     else if (error == VL_NOENT || error == VL_BADNAME) 
334         error = CM_ERROR_NOSUCHVOLUME;
335     return error;
336 }
337
338 cm_space_t *cm_GetSpace(void)
339 {
340         cm_space_t *tsp;
341
342         if (osi_Once(&cm_utilsOnce)) {
343                 lock_InitializeRWLock(&cm_utilsLock, "cm_utilsLock", LOCK_HIERARCHY_UTILS_GLOBAL);
344                 osi_EndOnce(&cm_utilsOnce);
345         }
346         
347         lock_ObtainWrite(&cm_utilsLock);
348         if (tsp = cm_spaceListp) {
349                 cm_spaceListp = tsp->nextp;
350         }
351         else tsp = (cm_space_t *) malloc(sizeof(cm_space_t));
352         (void) memset(tsp, 0, sizeof(cm_space_t));
353         lock_ReleaseWrite(&cm_utilsLock);
354         
355         return tsp;
356 }
357
358 void cm_FreeSpace(cm_space_t *tsp)
359 {
360         lock_ObtainWrite(&cm_utilsLock);
361         tsp->nextp = cm_spaceListp;
362         cm_spaceListp = tsp;
363         lock_ReleaseWrite(&cm_utilsLock);
364 }
365
366 /* characters that are legal in an 8.3 name */
367 /*
368  * We used to have 1's for all characters from 128 to 254.  But
369  * the NT client behaves better if we create an 8.3 name for any
370  * name that has a character with the high bit on, and if we
371  * delete those characters from 8.3 names.  In particular, see
372  * Sybase defect 10859.
373  */
374 char cm_LegalChars[256] = {
375  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
376  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
377  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
378  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
379  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
380  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
381  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
382  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
383  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
386  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
387  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
388  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
389  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
390  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
391 };
392
393 #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
394
395 /* return true iff component is a valid 8.3 name */
396 int cm_Is8Dot3(clientchar_t *namep)
397 {
398     int sawDot = 0;
399     clientchar_t tc;
400     int charCount = 0;
401         
402     /*
403      * can't have a leading dot;
404      * special case for . and ..
405      */
406     if (namep[0] == '.') {
407         if (namep[1] == 0)
408             return 1;
409         if (namep[1] == '.' && namep[2] == 0)
410             return 1;
411         return 0;
412     }
413     while (tc = *namep++) {
414         if (tc == '.') {
415             /* saw another dot */
416             if (sawDot) return 0;       /* second dot */
417             sawDot = 1;
418             charCount = 0;
419             continue;
420         }
421         if (!ISLEGALCHAR(tc))
422             return 0;
423         charCount++;
424         if (!sawDot && charCount > 8)
425             /* more than 8 chars in name */
426             return 0;
427         if (sawDot && charCount > 3)
428             /* more than 3 chars in extension */
429             return 0;
430     }
431     return 1;
432 }
433
434 /*
435  * Number unparsing map for generating 8.3 names;
436  * The version taken from DFS was on drugs.  
437  * You can't include '&' and '@' in a file name.
438  */
439 char cm_8Dot3Mapping[42] =
440 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
441  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
442  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
443  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '{', '}'
444 };
445 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
446
447 void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
448                         clientchar_t *shortName, clientchar_t **shortNameEndp)
449 {
450     char number[12];
451     int i, nsize = 0;
452     int vnode = ntohl(pfid->vnode);
453     char *lastDot;
454     int validExtension = 0;
455     char tc, *temp;
456     const char *name;
457
458     /* Unparse the file's vnode number to get a "uniquifier" */
459     do {
460         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
461         nsize++;
462         vnode /= cm_8Dot3MapSize;
463     } while (vnode);
464
465     /*
466      * Look for valid extension.  There has to be a dot, and
467      * at least one of the characters following has to be legal.
468      */
469     lastDot = strrchr(longname, '.');
470     if (lastDot) {
471         temp = lastDot; temp++;
472         while (tc = *temp++)
473             if (ISLEGALCHAR(tc))
474                 break;
475         if (tc)
476             validExtension = 1;
477     }
478
479     /* Copy name characters */
480     for (i = 0, name = longname;
481           i < (7 - nsize) && name != lastDot; ) {
482         tc = *name++;
483
484         if (tc == 0)
485             break;
486         if (!ISLEGALCHAR(tc))
487             continue;
488         i++;
489         *shortName++ = toupper(tc);
490     }
491
492     /* tilde */
493     *shortName++ = '~';
494
495     /* Copy uniquifier characters */
496     for (i=0; i < nsize; i++) {
497         *shortName++ = number[i];
498     }
499
500     if (validExtension) {
501         /* Copy extension characters */
502         *shortName++ = *lastDot++;      /* copy dot */
503         for (i = 0, tc = *lastDot++;
504              i < 3 && tc;
505              tc = *lastDot++) {
506             if (ISLEGALCHAR(tc)) {
507                 i++;
508                 *shortName++ = toupper(tc);
509             }
510         }
511     }
512
513     /* Trailing null */
514     *shortName = 0;
515
516     if (shortNameEndp)
517         *shortNameEndp = shortName;
518 }
519
520 void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
521                          clientchar_t *shortName, clientchar_t **shortNameEndp)
522 {
523     clientchar_t number[12];
524     int i, nsize = 0;
525     int vnode = ntohl(pfid->vnode);
526     clientchar_t *lastDot;
527     int validExtension = 0;
528     clientchar_t tc, *temp;
529     const clientchar_t *name;
530
531     /* Unparse the file's vnode number to get a "uniquifier" */
532     do {
533         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
534         nsize++;
535         vnode /= cm_8Dot3MapSize;
536     } while (vnode);
537
538     /*
539      * Look for valid extension.  There has to be a dot, and
540      * at least one of the characters following has to be legal.
541      */
542     lastDot = cm_ClientStrRChr(longname, '.');
543     if (lastDot) {
544         temp = lastDot; temp++;
545         while (tc = *temp++)
546             if (ISLEGALCHAR(tc))
547                 break;
548         if (tc)
549             validExtension = 1;
550     }
551
552     /* Copy name characters */
553     for (i = 0, name = longname;
554           i < (7 - nsize) && name != lastDot; ) {
555         tc = *name++;
556
557         if (tc == 0)
558             break;
559         if (!ISLEGALCHAR(tc))
560             continue;
561         i++;
562         *shortName++ = toupper((char) tc);
563     }
564
565     /* tilde */
566     *shortName++ = '~';
567
568     /* Copy uniquifier characters */
569     for (i=0; i < nsize; i++) {
570         *shortName++ = number[i];
571     }
572
573     if (validExtension) {
574         /* Copy extension characters */
575         *shortName++ = *lastDot++;      /* copy dot */
576         for (i = 0, tc = *lastDot++;
577              i < 3 && tc;
578              tc = *lastDot++) {
579             if (ISLEGALCHAR(tc)) {
580                 i++;
581                 *shortName++ = toupper(tc);
582             }
583         }
584     }
585
586     /* Trailing null */
587     *shortName = 0;
588
589     if (shortNameEndp)
590         *shortNameEndp = shortName;
591 }
592
593 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
594
595   \note This procedure works recursively calling itself.
596
597   \param[in] pattern string containing metacharacters.
598   \param[in] name File name to be compared with 'pattern'.
599
600   \return BOOL : TRUE/FALSE (match/mistmatch)
601 */
602 static BOOL 
603 szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold) 
604 {
605     clientchar_t upattern[MAX_PATH];
606     clientchar_t uname[MAX_PATH];
607
608     clientchar_t * pename;         // points to the last 'name' character
609     clientchar_t * p;
610     clientchar_t * pattern_next;
611
612     if (casefold) {
613         cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
614         cm_ClientStrUpr(upattern);
615         pattern = upattern;
616
617         cm_ClientStrCpy(uname, lengthof(uname), name);
618         cm_ClientStrUpr(uname);
619         name = uname;
620
621         /* The following translations all work on single byte
622            characters */
623         for (p=upattern; *p; p++) {
624             if (*p == '"') *p = '.'; continue;
625             if (*p == '<') *p = '*'; continue;
626             if (*p == '>') *p = '?'; continue;
627         }
628
629         for (p=uname; *p; p++) {
630             if (*p == '"') *p = '.'; continue;
631             if (*p == '<') *p = '*'; continue;
632             if (*p == '>') *p = '?'; continue;
633         }
634     }
635
636     pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
637
638     while (*name) {
639         switch (*pattern) {
640         case '?':
641             pattern = cm_ClientCharNext(pattern);
642             if (*name == '.')
643                 continue;
644             name = cm_ClientCharNext(name);
645             break;
646
647          case '*':
648             pattern = cm_ClientCharNext(pattern);
649             if (*pattern == '\0')
650                 return TRUE;
651
652             pattern_next = cm_ClientCharNext(pattern);
653
654             for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
655                 if (*p == *pattern &&
656                     szWildCardMatchFileName(pattern_next,
657                                             cm_ClientCharNext(p), FALSE))
658                     return TRUE;
659             } /* endfor */
660             if (*pattern == '.' && *pattern_next == '\0') {
661                 for (p = name; p && *p; p = cm_ClientCharNext(p))
662                     if (*p == '.')
663                         break;
664                 if (p && *p)
665                     return FALSE;
666                 return TRUE;
667             }
668             return FALSE;
669
670         default:
671             if (*name != *pattern)
672                 return FALSE;
673             pattern = cm_ClientCharNext(pattern);
674             name = cm_ClientCharNext(name);
675             break;
676         } /* endswitch */
677     } /* endwhile */
678
679     /* if all we have left are wildcards, then we match */
680     for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
681         if (*pattern != '*' && *pattern != '?')
682             return FALSE;
683     }
684     return TRUE;
685 }
686
687 /* do a case-folding search of the star name mask with the name in namep.
688  * Return 1 if we match, otherwise 0.
689  */
690 int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
691 {
692     clientchar_t *newmask, lastchar = _C('\0');
693     int    i, j, casefold, retval;
694     int  star = 0, qmark = 0, dot = 0;
695
696     /* make sure we only match 8.3 names, if requested */
697     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
698         return 0;
699
700     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
701
702     /* optimize the pattern:
703      * if there is a mixture of '?' and '*',
704      * for example  the sequence "*?*?*?*"
705      * must be turned into the form "*"
706      */
707     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+2)*sizeof(clientchar_t));
708     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
709         lastchar = maskp[i];
710         switch ( maskp[i] ) {
711         case '?':
712         case '>':
713             qmark++;
714             break;
715         case '<':
716         case '*':
717             star++;
718             break;
719         case '.':
720             dot++;
721             /* fallthrough */
722         default:
723             if ( star ) {
724                 newmask[j++] = '*';
725             } else if ( qmark ) {
726                 while ( qmark-- )
727                     newmask[j++] = '?';
728             }
729             newmask[j++] = maskp[i];
730             star = 0;
731             qmark = 0;
732         }
733     }
734     if ( star ) {
735         newmask[j++] = '*';
736     } else if ( qmark ) {
737         while ( qmark-- )
738             newmask[j++] = '?';
739     }
740     if (dot == 0 && lastchar == '<')
741         newmask[j++] = '.';
742     newmask[j++] = '\0';
743
744     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
745
746     free(newmask);
747     return retval;
748 }
749