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