Windows: Adjust error return values
[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 #include <string.h>
18 #include <malloc.h>
19 #define STRSAFE_NO_DEPRECATE
20 #include <strsafe.h>
21
22 #include "afsd.h"
23 #include <osi.h>
24 #include <rx/rx.h>
25
26 #include <afs/unified_afs.h>
27
28 static osi_once_t cm_utilsOnce;
29
30 osi_rwlock_t cm_utilsLock;
31
32 cm_space_t *cm_spaceListp;
33
34 static int et2sys[512];
35
36 static DWORD cm_TlsRequestSlot = -1;
37
38 void cm_utilsInit(void)
39 {
40     if (osi_Once(&cm_utilsOnce)) {
41         lock_InitializeRWLock(&cm_utilsLock, "cm_utilsLock", LOCK_HIERARCHY_UTILS_GLOBAL);
42
43         cm_TlsRequestSlot = TlsAlloc();
44
45         osi_EndOnce(&cm_utilsOnce);
46     }
47 }
48
49 void cm_utilsCleanup(void)
50 {
51     TlsFree(cm_TlsRequestSlot);
52 }
53
54 void
55 init_et_to_sys_error(void)
56 {
57     memset(&et2sys, 0, sizeof(et2sys));
58     et2sys[(UAEPERM - ERROR_TABLE_BASE_uae)] = EPERM;
59     et2sys[(UAENOENT - ERROR_TABLE_BASE_uae)] = ENOENT;
60     et2sys[(UAESRCH - ERROR_TABLE_BASE_uae)] = ESRCH;
61     et2sys[(UAEINTR - ERROR_TABLE_BASE_uae)] = EINTR;
62     et2sys[(UAEIO - ERROR_TABLE_BASE_uae)] = EIO;
63     et2sys[(UAENXIO - ERROR_TABLE_BASE_uae)] = ENXIO;
64     et2sys[(UAE2BIG - ERROR_TABLE_BASE_uae)] = E2BIG;
65     et2sys[(UAENOEXEC - ERROR_TABLE_BASE_uae)] = ENOEXEC;
66     et2sys[(UAEBADF - ERROR_TABLE_BASE_uae)] = EBADF;
67     et2sys[(UAECHILD - ERROR_TABLE_BASE_uae)] = ECHILD;
68     et2sys[(UAEAGAIN - ERROR_TABLE_BASE_uae)] = EAGAIN;
69     et2sys[(UAENOMEM - ERROR_TABLE_BASE_uae)] = ENOMEM;
70     et2sys[(UAEACCES - ERROR_TABLE_BASE_uae)] = EACCES;
71     et2sys[(UAEFAULT - ERROR_TABLE_BASE_uae)] = EFAULT;
72     et2sys[(UAENOTBLK - ERROR_TABLE_BASE_uae)] = ENOTBLK;
73     et2sys[(UAEBUSY - ERROR_TABLE_BASE_uae)] = EBUSY;
74     et2sys[(UAEEXIST - ERROR_TABLE_BASE_uae)] = EEXIST;
75     et2sys[(UAEXDEV - ERROR_TABLE_BASE_uae)] = EXDEV;
76     et2sys[(UAENODEV - ERROR_TABLE_BASE_uae)] = ENODEV;
77     et2sys[(UAENOTDIR - ERROR_TABLE_BASE_uae)] = ENOTDIR;
78     et2sys[(UAEISDIR - ERROR_TABLE_BASE_uae)] = EISDIR;
79     et2sys[(UAEINVAL - ERROR_TABLE_BASE_uae)] = EINVAL;
80     et2sys[(UAENFILE - ERROR_TABLE_BASE_uae)] = ENFILE;
81     et2sys[(UAEMFILE - ERROR_TABLE_BASE_uae)] = EMFILE;
82     et2sys[(UAENOTTY - ERROR_TABLE_BASE_uae)] = ENOTTY;
83     et2sys[(UAETXTBSY - ERROR_TABLE_BASE_uae)] = ETXTBSY;
84     et2sys[(UAEFBIG - ERROR_TABLE_BASE_uae)] = EFBIG;
85     et2sys[(UAENOSPC - ERROR_TABLE_BASE_uae)] = ENOSPC;
86     et2sys[(UAESPIPE - ERROR_TABLE_BASE_uae)] = ESPIPE;
87     et2sys[(UAEROFS - ERROR_TABLE_BASE_uae)] = EROFS;
88     et2sys[(UAEMLINK - ERROR_TABLE_BASE_uae)] = EMLINK;
89     et2sys[(UAEPIPE - ERROR_TABLE_BASE_uae)] = EPIPE;
90     et2sys[(UAEDOM - ERROR_TABLE_BASE_uae)] = EDOM;
91     et2sys[(UAERANGE - ERROR_TABLE_BASE_uae)] = ERANGE;
92     et2sys[(UAEDEADLK - ERROR_TABLE_BASE_uae)] = EDEADLK;
93     et2sys[(UAENAMETOOLONG - ERROR_TABLE_BASE_uae)] = ENAMETOOLONG;
94     et2sys[(UAENOLCK - ERROR_TABLE_BASE_uae)] = ENOLCK;
95     et2sys[(UAENOSYS - ERROR_TABLE_BASE_uae)] = ENOSYS;
96     et2sys[(UAENOTEMPTY - ERROR_TABLE_BASE_uae)] = ENOTEMPTY;
97     et2sys[(UAELOOP - ERROR_TABLE_BASE_uae)] = ELOOP;
98     et2sys[(UAEWOULDBLOCK - ERROR_TABLE_BASE_uae)] = EWOULDBLOCK;
99     et2sys[(UAENOMSG - ERROR_TABLE_BASE_uae)] = ENOMSG;
100     et2sys[(UAEIDRM - ERROR_TABLE_BASE_uae)] = EIDRM;
101     et2sys[(UAECHRNG - ERROR_TABLE_BASE_uae)] = ECHRNG;
102     et2sys[(UAEL2NSYNC - ERROR_TABLE_BASE_uae)] = EL2NSYNC;
103     et2sys[(UAEL3HLT - ERROR_TABLE_BASE_uae)] = EL3HLT;
104     et2sys[(UAEL3RST - ERROR_TABLE_BASE_uae)] = EL3RST;
105     et2sys[(UAELNRNG - ERROR_TABLE_BASE_uae)] = ELNRNG;
106     et2sys[(UAEUNATCH - ERROR_TABLE_BASE_uae)] = EUNATCH;
107     et2sys[(UAENOCSI - ERROR_TABLE_BASE_uae)] = ENOCSI;
108     et2sys[(UAEL2HLT - ERROR_TABLE_BASE_uae)] = EL2HLT;
109     et2sys[(UAEBADE - ERROR_TABLE_BASE_uae)] = EBADE;
110     et2sys[(UAEBADR - ERROR_TABLE_BASE_uae)] = EBADR;
111     et2sys[(UAEXFULL - ERROR_TABLE_BASE_uae)] = EXFULL;
112     et2sys[(UAENOANO - ERROR_TABLE_BASE_uae)] = ENOANO;
113     et2sys[(UAEBADRQC - ERROR_TABLE_BASE_uae)] = EBADRQC;
114     et2sys[(UAEBADSLT - ERROR_TABLE_BASE_uae)] = EBADSLT;
115     et2sys[(UAEBFONT - ERROR_TABLE_BASE_uae)] = EBFONT;
116     et2sys[(UAENOSTR - ERROR_TABLE_BASE_uae)] = ENOSTR;
117     et2sys[(UAENODATA - ERROR_TABLE_BASE_uae)] = ENODATA;
118     et2sys[(UAETIME - ERROR_TABLE_BASE_uae)] = ETIME;
119     et2sys[(UAENOSR - ERROR_TABLE_BASE_uae)] = ENOSR;
120     et2sys[(UAENONET - ERROR_TABLE_BASE_uae)] = ENONET;
121     et2sys[(UAENOPKG - ERROR_TABLE_BASE_uae)] = ENOPKG;
122     et2sys[(UAEREMOTE - ERROR_TABLE_BASE_uae)] = EREMOTE;
123     et2sys[(UAENOLINK - ERROR_TABLE_BASE_uae)] = ENOLINK;
124     et2sys[(UAEADV - ERROR_TABLE_BASE_uae)] = EADV;
125     et2sys[(UAESRMNT - ERROR_TABLE_BASE_uae)] = ESRMNT;
126     et2sys[(UAECOMM - ERROR_TABLE_BASE_uae)] = ECOMM;
127     et2sys[(UAEPROTO - ERROR_TABLE_BASE_uae)] = EPROTO;
128     et2sys[(UAEMULTIHOP - ERROR_TABLE_BASE_uae)] = EMULTIHOP;
129     et2sys[(UAEDOTDOT - ERROR_TABLE_BASE_uae)] = EDOTDOT;
130     et2sys[(UAEBADMSG - ERROR_TABLE_BASE_uae)] = EBADMSG;
131     et2sys[(UAEOVERFLOW - ERROR_TABLE_BASE_uae)] = EOVERFLOW;
132     et2sys[(UAENOTUNIQ - ERROR_TABLE_BASE_uae)] = ENOTUNIQ;
133     et2sys[(UAEBADFD - ERROR_TABLE_BASE_uae)] = EBADFD;
134     et2sys[(UAEREMCHG - ERROR_TABLE_BASE_uae)] = EREMCHG;
135     et2sys[(UAELIBACC - ERROR_TABLE_BASE_uae)] = ELIBACC;
136     et2sys[(UAELIBBAD - ERROR_TABLE_BASE_uae)] = ELIBBAD;
137     et2sys[(UAELIBSCN - ERROR_TABLE_BASE_uae)] = ELIBSCN;
138     et2sys[(UAELIBMAX - ERROR_TABLE_BASE_uae)] = ELIBMAX;
139     et2sys[(UAELIBEXEC - ERROR_TABLE_BASE_uae)] = ELIBEXEC;
140     et2sys[(UAEILSEQ - ERROR_TABLE_BASE_uae)] = EILSEQ;
141     et2sys[(UAERESTART - ERROR_TABLE_BASE_uae)] = ERESTART;
142     et2sys[(UAESTRPIPE - ERROR_TABLE_BASE_uae)] = ESTRPIPE;
143     et2sys[(UAEUSERS - ERROR_TABLE_BASE_uae)] = EUSERS;
144     et2sys[(UAENOTSOCK - ERROR_TABLE_BASE_uae)] = ENOTSOCK;
145     et2sys[(UAEDESTADDRREQ - ERROR_TABLE_BASE_uae)] = EDESTADDRREQ;
146     et2sys[(UAEMSGSIZE - ERROR_TABLE_BASE_uae)] = EMSGSIZE;
147     et2sys[(UAEPROTOTYPE - ERROR_TABLE_BASE_uae)] = EPROTOTYPE;
148     et2sys[(UAENOPROTOOPT - ERROR_TABLE_BASE_uae)] = ENOPROTOOPT;
149     et2sys[(UAEPROTONOSUPPORT - ERROR_TABLE_BASE_uae)] = EPROTONOSUPPORT;
150     et2sys[(UAESOCKTNOSUPPORT - ERROR_TABLE_BASE_uae)] = ESOCKTNOSUPPORT;
151     et2sys[(UAEOPNOTSUPP - ERROR_TABLE_BASE_uae)] = EOPNOTSUPP;
152     et2sys[(UAEPFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EPFNOSUPPORT;
153     et2sys[(UAEAFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EAFNOSUPPORT;
154     et2sys[(UAEADDRINUSE - ERROR_TABLE_BASE_uae)] = EADDRINUSE;
155     et2sys[(UAEADDRNOTAVAIL - ERROR_TABLE_BASE_uae)] = EADDRNOTAVAIL;
156     et2sys[(UAENETDOWN - ERROR_TABLE_BASE_uae)] = ENETDOWN;
157     et2sys[(UAENETUNREACH - ERROR_TABLE_BASE_uae)] = ENETUNREACH;
158     et2sys[(UAENETRESET - ERROR_TABLE_BASE_uae)] = ENETRESET;
159     et2sys[(UAECONNABORTED - ERROR_TABLE_BASE_uae)] = ECONNABORTED;
160     et2sys[(UAECONNRESET - ERROR_TABLE_BASE_uae)] = ECONNRESET;
161     et2sys[(UAENOBUFS - ERROR_TABLE_BASE_uae)] = ENOBUFS;
162     et2sys[(UAEISCONN - ERROR_TABLE_BASE_uae)] = EISCONN;
163     et2sys[(UAENOTCONN - ERROR_TABLE_BASE_uae)] = ENOTCONN;
164     et2sys[(UAESHUTDOWN - ERROR_TABLE_BASE_uae)] = ESHUTDOWN;
165     et2sys[(UAETOOMANYREFS - ERROR_TABLE_BASE_uae)] = ETOOMANYREFS;
166     et2sys[(UAETIMEDOUT - ERROR_TABLE_BASE_uae)] = ETIMEDOUT;
167     et2sys[(UAECONNREFUSED - ERROR_TABLE_BASE_uae)] = ECONNREFUSED;
168     et2sys[(UAEHOSTDOWN - ERROR_TABLE_BASE_uae)] = EHOSTDOWN;
169     et2sys[(UAEHOSTUNREACH - ERROR_TABLE_BASE_uae)] = EHOSTUNREACH;
170     et2sys[(UAEALREADY - ERROR_TABLE_BASE_uae)] = EALREADY;
171     et2sys[(UAEINPROGRESS - ERROR_TABLE_BASE_uae)] = EINPROGRESS;
172     et2sys[(UAESTALE - ERROR_TABLE_BASE_uae)] = ESTALE;
173     et2sys[(UAEUCLEAN - ERROR_TABLE_BASE_uae)] = EUCLEAN;
174     et2sys[(UAENOTNAM - ERROR_TABLE_BASE_uae)] = ENOTNAM;
175     et2sys[(UAENAVAIL - ERROR_TABLE_BASE_uae)] = ENAVAIL;
176     et2sys[(UAEISNAM - ERROR_TABLE_BASE_uae)] = EISNAM;
177     et2sys[(UAEREMOTEIO - ERROR_TABLE_BASE_uae)] = EREMOTEIO;
178     et2sys[(UAEDQUOT - ERROR_TABLE_BASE_uae)] = EDQUOT;
179     et2sys[(UAENOMEDIUM - ERROR_TABLE_BASE_uae)] = ENOMEDIUM;
180     et2sys[(UAEMEDIUMTYPE - ERROR_TABLE_BASE_uae)] = EMEDIUMTYPE;
181 }
182
183 static afs_int32
184 et_to_sys_error(afs_int32 in)
185 {
186     if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512)
187         return in;
188     if (et2sys[in - ERROR_TABLE_BASE_uae] != 0)
189         return et2sys[in - ERROR_TABLE_BASE_uae];
190     return in;
191 }
192
193 long cm_MapRPCError(long error, cm_req_t *reqp)
194 {
195     if (error == 0) 
196         return 0;
197
198     /* If we had to stop retrying, report our saved error code. */
199     if (reqp && error == CM_ERROR_TIMEDOUT) {
200         if (reqp->accessError)
201             return reqp->accessError;
202         if (reqp->volumeError)
203             return reqp->volumeError;
204         if (reqp->rpcError)
205             return reqp->rpcError;
206         return error;
207     }
208
209     error = et_to_sys_error(error);
210
211     if (error == RX_CALL_DEAD ||
212         error == RX_CALL_TIMEOUT ||
213         error == RX_RESTARTING)
214         error = CM_ERROR_RETRY;
215     else if (error < 0)
216         error = CM_ERROR_UNKNOWN;
217     else if (error == EROFS) 
218         error = CM_ERROR_READONLY;
219     else if (error == EACCES) 
220         error = CM_ERROR_NOACCESS;
221     else if (error == EXDEV) 
222         error = CM_ERROR_CROSSDEVLINK;
223     else if (error == EEXIST) 
224         error = CM_ERROR_EXISTS;
225     else if (error == ENOTDIR) 
226         error = CM_ERROR_NOTDIR;
227     else if (error == ENOENT)
228         error = CM_ERROR_NOSUCHFILE;
229     else if (error == EAGAIN
230              || error == 35        /* EAGAIN, Digital UNIX */
231              || error == WSAEWOULDBLOCK)
232         error = CM_ERROR_WOULDBLOCK;
233     else if (error == VDISKFULL
234               || error == ENOSPC)
235         error = CM_ERROR_SPACE;
236     else if (error == VOVERQUOTA
237               || error == EDQUOT
238               || error == 49    /* EDQUOT on Solaris */
239               || error == 88    /* EDQUOT on AIX */
240               || error == 69    /* EDQUOT on Digital UNIX and HPUX */
241               || error == 122   /* EDQUOT on Linux */
242               || error == 1133) /* EDQUOT on Irix  */
243         error = CM_ERROR_QUOTA;
244     else if (error == VNOVNODE)
245         error = CM_ERROR_BADFD;
246     else if (error == VNOSERVICE || error == VSALVAGE || error == VOFFLINE)
247         error = CM_ERROR_ALLOFFLINE;
248     else if (error == EISDIR)
249         return CM_ERROR_ISDIR;
250     return error;
251 }
252
253 long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
254 {
255     if (error == 0) 
256         return 0;
257
258     /* If we had to stop retrying, report our saved error code. */
259     if (reqp && error == CM_ERROR_TIMEDOUT) {
260         if (reqp->accessError)
261             return reqp->accessError;
262         if (reqp->volumeError)
263             return reqp->volumeError;
264         if (reqp->rpcError)
265             return reqp->rpcError;
266         return error;
267     }
268
269     error = et_to_sys_error(error);
270
271     if (error == RX_CALL_DEAD ||
272         error == RX_CALL_TIMEOUT ||
273         error == RX_RESTARTING)
274         error = CM_ERROR_RETRY;
275     else if (error < 0)
276         error = CM_ERROR_UNKNOWN;
277     else if (error == EROFS) 
278         error = CM_ERROR_READONLY;
279     else if (error == ENOTDIR) 
280         error = CM_ERROR_NOTDIR;
281     else if (error == EACCES) 
282         error = CM_ERROR_NOACCESS;
283     else if (error == ENOENT) 
284         error = CM_ERROR_NOSUCHFILE;
285     else if (error == ENOTEMPTY 
286               || error == 17            /* AIX */
287               || error == 66            /* SunOS 4, Digital UNIX */
288               || error == 93            /* Solaris 2, IRIX */
289               || error == 247)  /* HP/UX */
290         error = CM_ERROR_NOTEMPTY;
291     return error;
292 }       
293
294 long cm_MapVLRPCError(long error, cm_req_t *reqp)
295 {
296     if (error == 0) return 0;
297
298     /* If we had to stop retrying, report our saved error code. */
299     if (reqp && error == CM_ERROR_TIMEDOUT) {
300         if (reqp->accessError)
301             return reqp->accessError;
302         if (reqp->volumeError)
303             return reqp->volumeError;
304         if (reqp->rpcError)
305             return reqp->rpcError;
306         return error;
307     }
308
309     error = et_to_sys_error(error);
310
311     if (error == RX_CALL_DEAD ||
312         error == RX_CALL_TIMEOUT ||
313         error == RX_RESTARTING)
314         error = CM_ERROR_RETRY;
315     else if (error < 0)
316         error = CM_ERROR_UNKNOWN;
317     else if (error == VL_NOENT || error == VL_BADNAME) 
318         error = CM_ERROR_NOSUCHVOLUME;
319     return error;
320 }
321
322 cm_space_t *cm_GetSpace(void)
323 {
324         cm_space_t *tsp;
325
326         cm_utilsInit();
327
328         lock_ObtainWrite(&cm_utilsLock);
329         if (tsp = cm_spaceListp) {
330                 cm_spaceListp = tsp->nextp;
331         }
332         else tsp = (cm_space_t *) malloc(sizeof(cm_space_t));
333         (void) memset(tsp, 0, sizeof(cm_space_t));
334         lock_ReleaseWrite(&cm_utilsLock);
335         
336         return tsp;
337 }
338
339 void cm_FreeSpace(cm_space_t *tsp)
340 {
341         lock_ObtainWrite(&cm_utilsLock);
342         tsp->nextp = cm_spaceListp;
343         cm_spaceListp = tsp;
344         lock_ReleaseWrite(&cm_utilsLock);
345 }
346
347 /* characters that are legal in an 8.3 name */
348 /*
349  * We used to have 1's for all characters from 128 to 254.  But
350  * the NT client behaves better if we create an 8.3 name for any
351  * name that has a character with the high bit on, and if we
352  * delete those characters from 8.3 names.  In particular, see
353  * Sybase defect 10859.
354  */
355 char cm_LegalChars[256] = {
356  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
359  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
360  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
361  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
362  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
363  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
364  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
371  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
372 };
373
374 #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
375
376 /* return true iff component is a valid 8.3 name */
377 int cm_Is8Dot3(clientchar_t *namep)
378 {
379     int sawDot = 0;
380     clientchar_t tc;
381     int charCount = 0;
382     
383     if (namep == NULL || !namep[0])
384         return 0;
385
386     /*
387      * can't have a leading dot;
388      * special case for . and ..
389      */
390     if (namep[0] == '.') {
391         if (namep[1] == 0)
392             return 1;
393         if (namep[1] == '.' && namep[2] == 0)
394             return 1;
395         return 0;
396     }
397     while (tc = *namep++) {
398         if (tc == '.') {
399             /* saw another dot */
400             if (sawDot) return 0;       /* second dot */
401             sawDot = 1;
402             charCount = 0;
403             continue;
404         }
405         if (!ISLEGALCHAR(tc))
406             return 0;
407         charCount++;
408         if (!sawDot && charCount > 8)
409             /* more than 8 chars in name */
410             return 0;
411         if (sawDot && charCount > 3)
412             /* more than 3 chars in extension */
413             return 0;
414     }
415     return 1;
416 }
417
418 /*
419  * Number unparsing map for generating 8.3 names;
420  * The version taken from DFS was on drugs.  
421  * You can't include '&' and '@' in a file name.
422  */
423 char cm_8Dot3Mapping[42] =
424 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
425  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
426  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
427  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '{', '}'
428 };
429 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
430
431 void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
432                         clientchar_t *shortName, clientchar_t **shortNameEndp)
433 {
434     char number[12];
435     int i, nsize = 0;
436     int vnode = ntohl(pfid->vnode);
437     char *lastDot;
438     int validExtension = 0;
439     char tc, *temp;
440     const char *name;
441
442     /* Unparse the file's vnode number to get a "uniquifier" */
443     do {
444         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
445         nsize++;
446         vnode /= cm_8Dot3MapSize;
447     } while (vnode);
448
449     /*
450      * Look for valid extension.  There has to be a dot, and
451      * at least one of the characters following has to be legal.
452      */
453     lastDot = strrchr(longname, '.');
454     if (lastDot) {
455         temp = lastDot; temp++;
456         while (tc = *temp++)
457             if (ISLEGALCHAR(tc))
458                 break;
459         if (tc)
460             validExtension = 1;
461     }
462
463     /* Copy name characters */
464     for (i = 0, name = longname;
465           i < (7 - nsize) && name != lastDot; ) {
466         tc = *name++;
467
468         if (tc == 0)
469             break;
470         if (!ISLEGALCHAR(tc))
471             continue;
472         i++;
473         *shortName++ = toupper(tc);
474     }
475
476     /* tilde */
477     *shortName++ = '~';
478
479     /* Copy uniquifier characters */
480     for (i=0; i < nsize; i++) {
481         *shortName++ = number[i];
482     }
483
484     if (validExtension) {
485         /* Copy extension characters */
486         *shortName++ = *lastDot++;      /* copy dot */
487         for (i = 0, tc = *lastDot++;
488              i < 3 && tc;
489              tc = *lastDot++) {
490             if (ISLEGALCHAR(tc)) {
491                 i++;
492                 *shortName++ = toupper(tc);
493             }
494         }
495     }
496
497     /* Trailing null */
498     *shortName = 0;
499
500     if (shortNameEndp)
501         *shortNameEndp = shortName;
502 }
503
504 void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
505                          clientchar_t *shortName, clientchar_t **shortNameEndp)
506 {
507     clientchar_t number[12];
508     int i, nsize = 0;
509     int vnode = ntohl(pfid->vnode);
510     clientchar_t *lastDot;
511     int validExtension = 0;
512     clientchar_t tc, *temp;
513     const clientchar_t *name;
514
515     /* Unparse the file's vnode number to get a "uniquifier" */
516     do {
517         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
518         nsize++;
519         vnode /= cm_8Dot3MapSize;
520     } while (vnode);
521
522     /*
523      * Look for valid extension.  There has to be a dot, and
524      * at least one of the characters following has to be legal.
525      */
526     lastDot = cm_ClientStrRChr(longname, '.');
527     if (lastDot) {
528         temp = lastDot; temp++;
529         while (tc = *temp++)
530             if (ISLEGALCHAR(tc))
531                 break;
532         if (tc)
533             validExtension = 1;
534     }
535
536     /* Copy name characters */
537     for (i = 0, name = longname;
538           i < (7 - nsize) && name != lastDot; ) {
539         tc = *name++;
540
541         if (tc == 0)
542             break;
543         if (!ISLEGALCHAR(tc))
544             continue;
545         i++;
546         *shortName++ = toupper((char) tc);
547     }
548
549     /* tilde */
550     *shortName++ = '~';
551
552     /* Copy uniquifier characters */
553     for (i=0; i < nsize; i++) {
554         *shortName++ = number[i];
555     }
556
557     if (validExtension) {
558         /* Copy extension characters */
559         *shortName++ = *lastDot++;      /* copy dot */
560         for (i = 0, tc = *lastDot++;
561              i < 3 && tc;
562              tc = *lastDot++) {
563             if (ISLEGALCHAR(tc)) {
564                 i++;
565                 *shortName++ = toupper(tc);
566             }
567         }
568     }
569
570     /* Trailing null */
571     *shortName = 0;
572
573     if (shortNameEndp)
574         *shortNameEndp = shortName;
575 }
576
577 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
578
579   \note This procedure works recursively calling itself.
580
581   \param[in] pattern string containing metacharacters.
582   \param[in] name File name to be compared with 'pattern'.
583
584   \return BOOL : TRUE/FALSE (match/mistmatch)
585 */
586 static BOOL 
587 szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold) 
588 {
589     clientchar_t upattern[MAX_PATH];
590     clientchar_t uname[MAX_PATH];
591
592     clientchar_t * pename;         // points to the last 'name' character
593     clientchar_t * p;
594     clientchar_t * pattern_next;
595
596     if (casefold) {
597         cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
598         cm_ClientStrUpr(upattern);
599         pattern = upattern;
600
601         cm_ClientStrCpy(uname, lengthof(uname), name);
602         cm_ClientStrUpr(uname);
603         name = uname;
604
605         /* The following translations all work on single byte
606            characters */
607         for (p=upattern; *p; p++) {
608             if (*p == '"') *p = '.'; continue;
609             if (*p == '<') *p = '*'; continue;
610             if (*p == '>') *p = '?'; continue;
611         }
612
613         for (p=uname; *p; p++) {
614             if (*p == '"') *p = '.'; continue;
615             if (*p == '<') *p = '*'; continue;
616             if (*p == '>') *p = '?'; continue;
617         }
618     }
619
620     pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
621
622     while (*name) {
623         switch (*pattern) {
624         case '?':
625             pattern = cm_ClientCharNext(pattern);
626             if (*name == '.')
627                 continue;
628             name = cm_ClientCharNext(name);
629             break;
630
631          case '*':
632             pattern = cm_ClientCharNext(pattern);
633             if (*pattern == '\0')
634                 return TRUE;
635
636             pattern_next = cm_ClientCharNext(pattern);
637
638             for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
639                 if (*p == *pattern &&
640                     szWildCardMatchFileName(pattern_next,
641                                             cm_ClientCharNext(p), FALSE))
642                     return TRUE;
643             } /* endfor */
644             if (*pattern == '.' && *pattern_next == '\0') {
645                 for (p = name; p && *p; p = cm_ClientCharNext(p))
646                     if (*p == '.')
647                         break;
648                 if (p && *p)
649                     return FALSE;
650                 return TRUE;
651             }
652             return FALSE;
653
654         default:
655             if (*name != *pattern)
656                 return FALSE;
657             pattern = cm_ClientCharNext(pattern);
658             name = cm_ClientCharNext(name);
659             break;
660         } /* endswitch */
661     } /* endwhile */
662
663     /* if all we have left are wildcards, then we match */
664     for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
665         if (*pattern != '*' && *pattern != '?')
666             return FALSE;
667     }
668     return TRUE;
669 }
670
671 /* do a case-folding search of the star name mask with the name in namep.
672  * Return 1 if we match, otherwise 0.
673  */
674 int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
675 {
676     clientchar_t *newmask, lastchar = _C('\0');
677     int    i, j, casefold, retval;
678     int  star = 0, qmark = 0, dot = 0;
679
680     /* make sure we only match 8.3 names, if requested */
681     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
682         return 0;
683
684     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
685
686     /* optimize the pattern:
687      * if there is a mixture of '?' and '*',
688      * for example  the sequence "*?*?*?*"
689      * must be turned into the form "*"
690      */
691     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+2)*sizeof(clientchar_t));
692     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
693         lastchar = maskp[i];
694         switch ( maskp[i] ) {
695         case '?':
696         case '>':
697             qmark++;
698             break;
699         case '<':
700         case '*':
701             star++;
702             break;
703         case '.':
704             dot++;
705             /* fallthrough */
706         default:
707             if ( star ) {
708                 newmask[j++] = '*';
709             } else if ( qmark ) {
710                 while ( qmark-- )
711                     newmask[j++] = '?';
712             }
713             newmask[j++] = maskp[i];
714             star = 0;
715             qmark = 0;
716         }
717     }
718     if ( star ) {
719         newmask[j++] = '*';
720     } else if ( qmark ) {
721         while ( qmark-- )
722             newmask[j++] = '?';
723     }
724     if (dot == 0 && lastchar == '<')
725         newmask[j++] = '.';
726     newmask[j++] = '\0';
727
728     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
729
730     free(newmask);
731     return retval;
732 }
733
734 BOOL
735 cm_TargetPerceivedAsDirectory(const fschar_t *target)
736 {
737     char        * ext;
738
739     ext = PathFindExtension(target);
740     if (!ext[0])
741         return TRUE;
742
743     return FALSE;
744 }
745
746 HANDLE 
747 cm_LoadAfsdHookLib(void)
748 {
749     char dllname[260];
750     char *p;
751     HANDLE hLib;
752
753     if (!GetModuleFileName(NULL, dllname, sizeof(dllname)))
754         return NULL;
755
756     p = strrchr(dllname, '\\');
757     if (p) {
758         p++;
759         strcpy(p, AFSD_HOOK_DLL);
760         hLib = LoadLibrary(dllname);
761     } else {
762         hLib = LoadLibrary(AFSD_HOOK_DLL);
763     }
764
765     return hLib;
766 }
767
768 /*
769  * Obtain the file info structure for the specified file.
770  * If a full path is not specified, the search order is the
771  * same as that used by LoadLibrary().
772  */
773 BOOL
774 cm_GetOSFileVersion (char *filename, LARGE_INTEGER *liVer)
775 {
776     DWORD dwHandle;
777     DWORD dwSize;
778     char* pInfo = NULL;
779     BOOL  rc;
780     UINT uLen;
781     void *pbuf;
782     VS_FIXEDFILEINFO vsf;
783
784     dwSize = GetFileVersionInfoSizeA(filename,&dwHandle);
785     if (dwSize == 0) {
786         rc = FALSE;
787         goto done;
788     }
789     pInfo = (char*)malloc(dwSize);
790     if (!pInfo) {
791         rc = FALSE;
792         goto done;
793     }
794     rc = GetFileVersionInfoA(filename, dwHandle, dwSize, pInfo);
795     if (!rc)
796         goto done;
797     rc = VerQueryValueA(pInfo,"\\",&pbuf, &uLen);
798     if (!rc)
799         goto done;
800     memcpy(&vsf, pbuf, sizeof(VS_FIXEDFILEINFO));
801
802     liVer->LowPart = vsf.dwFileVersionLS;
803     liVer->HighPart = vsf.dwFileVersionMS;
804     rc = TRUE;
805
806   done:
807     if (pInfo)
808         free(pInfo);
809     return rc;
810 }
811
812 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
813 typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID *);
814 typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID);
815
816 BOOL msftSMBRedirectorSupportsExtendedTimeouts(void) 
817 {
818     static BOOL fChecked = FALSE;
819     static BOOL fSupportsExtendedTimeouts = FALSE;
820
821     if (!fChecked)
822     {
823         BOOL isWow64 = FALSE;
824         OSVERSIONINFOEX Version;
825         HANDLE h1 = NULL;
826         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
827         LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection = NULL;
828         LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection = NULL;
829         PVOID Wow64RedirectionState;
830         LARGE_INTEGER fvFile, fvHotFixMin;
831
832         h1 = GetModuleHandle("kernel32.dll"); /* no refcount increase */
833         /* 
834          * If we don't find the fnIsWow64Process function then we
835          * are not running in a Wow64 environment
836          */
837         fnIsWow64Process =
838             (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process");
839
840         memset (&Version, 0x00, sizeof(Version));
841         Version.dwOSVersionInfoSize = sizeof(Version);
842         GetVersionEx((OSVERSIONINFO *) &Version);
843
844         /* 
845          * Support is available as hot fixes / service packs on:
846          *   XP SP2
847          *   XP SP3
848          *   2003 and XP64 SP2
849          *   Vista and 2008 SP2
850          *   Win7 and 2008 R2
851          */
852         if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
853             Version.dwMajorVersion >= 5) {
854
855             /* 32-bit XP */
856             if (Version.dwMajorVersion == 5 &&
857                 Version.dwMinorVersion == 1) {
858                 
859                 fvHotFixMin.HighPart = (5 << 16) | 1;
860
861                 switch (Version.wServicePackMajor) {
862                 case 3:
863                     fvHotFixMin.LowPart = (2600 << 16) | 5815;
864                     break;
865                 case 2:
866                     fvHotFixMin.LowPart = (2600 << 16) | 3572;
867                     break;
868                 default:
869                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 3);
870                     goto checked;
871                 }
872             }
873
874             /* 64-bit XP and Server 2003 */
875             else if (Version.dwMajorVersion == 5 &&
876                      Version.dwMinorVersion == 2) {
877                 
878                 fvHotFixMin.HighPart = (5 << 16) | 2;
879
880                 switch (Version.wServicePackMajor) {
881                 case 2:
882                     fvHotFixMin.LowPart = (3790 << 16) | 4479;
883                     break;
884                 case 1:
885                     fvHotFixMin.LowPart = (3790 << 16) | 3310;
886                     break;
887                 default:
888                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
889                     goto checked;
890                 }
891             }
892
893             /* Vista and Server 2008 */
894             else if (Version.dwMajorVersion == 6 &&
895                      Version.dwMinorVersion == 0) {
896                 
897                 fvHotFixMin.HighPart = (6 << 16) | 0;
898
899                 switch (Version.wServicePackMajor) {
900                 case 2:
901                     fvHotFixMin.LowPart = (6002 << 16) | 18005;
902                     break;
903                 default:
904                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
905                     goto checked;
906                 }
907             }
908
909             /* Windows 7 and Server 2008 R2 and beyond */
910             else if (Version.dwMajorVersion > 6 ||
911                      Version.dwMajorVersion == 6 &&
912                      Version.dwMinorVersion >= 1) {
913                 fSupportsExtendedTimeouts = TRUE;
914                 goto checked;
915             }
916
917             /* If wow64, disable wow64 redirection and preserve the existing state */
918             if (fnIsWow64Process && 
919                  fnIsWow64Process(GetCurrentProcess(), &isWow64) &&
920                  isWow64) {
921                 fnDisableWow64FsRedirection =
922                     (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64DisableWow64FsRedirection");
923                 fnRevertWow64FsRedirection =
924                     (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64RevertWow64FsRedirection");
925                 fnDisableWow64FsRedirection(&Wow64RedirectionState);
926             }
927             
928             if (cm_GetOSFileVersion("drivers\\mrxsmb.sys", &fvFile) ||
929                 (fvFile.QuadPart >= fvHotFixMin.QuadPart))
930                 fSupportsExtendedTimeouts = TRUE;
931
932             /* If wow64, restore the previous redirection state */
933             if (fnIsWow64Process && isWow64) {
934                 fnRevertWow64FsRedirection(Wow64RedirectionState);
935             }            
936         }
937       checked:
938         fChecked = TRUE;
939     }
940
941     return fSupportsExtendedTimeouts;
942 }
943
944 void cm_ResetServerPriority()
945 {
946     void * p = TlsGetValue(cm_TlsRequestSlot);
947     if (p) {
948         free(p);
949         TlsSetValue(cm_TlsRequestSlot, NULL);
950         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
951     }
952 }
953
954 void cm_SetRequestStartTime()
955 {
956     time_t * tp = TlsGetValue(cm_TlsRequestSlot);
957     if (!tp)
958         tp = malloc(sizeof(time_t));
959     if (tp) {
960         *tp = osi_Time();
961
962         if (!TlsSetValue(cm_TlsRequestSlot, tp))
963             free(tp);
964     }   
965 }
966
967 void cm_UpdateServerPriority()
968 {       
969     time_t *tp = TlsGetValue(cm_TlsRequestSlot);
970
971     if (tp) {
972         time_t now = osi_Time();
973
974         /* Give one priority boost for each 15 seconds */
975         SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
976     }
977 }
978
979
980 void cm_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
981 {
982     // Note that LONGLONG is a 64-bit value
983     LONGLONG ll;
984
985     ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
986     largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
987     largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
988 }
989
990 void cm_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
991 {
992     // Note that LONGLONG is a 64-bit value
993     LONGLONG ll;
994
995     ll = largeTimep->dwHighDateTime;
996     ll <<= 32;
997     ll += largeTimep->dwLowDateTime;
998
999     ll -= 116444736000000000;
1000     ll /= 10000000;
1001
1002     *unixTimep = (DWORD)ll;
1003 }
1004
1005 void cm_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
1006 {
1007     struct tm *ltp;
1008     int dosDate;
1009     int dosTime;
1010     struct tm localJunk;
1011     time_t t = unixTime;
1012
1013     ltp = localtime(&t);
1014
1015     /* if we fail, make up something */
1016     if (!ltp) {
1017         ltp = &localJunk;
1018         localJunk.tm_year = 89 - 20;
1019         localJunk.tm_mon = 4;
1020         localJunk.tm_mday = 12;
1021         localJunk.tm_hour = 0;
1022         localJunk.tm_min = 0;
1023         localJunk.tm_sec = 0;
1024     }   
1025
1026     dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
1027     dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
1028     *searchTimep = (dosDate<<16) | dosTime;
1029 }       
1030
1031 void cm_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
1032 {
1033     unsigned short dosDate;
1034     unsigned short dosTime;
1035     struct tm localTm;
1036         
1037     dosDate = (unsigned short) (searchTime & 0xffff);
1038     dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
1039
1040     localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
1041     localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;        /* January is 0 in localTm */
1042     localTm.tm_mday = (dosDate) & 0x1f;
1043     localTm.tm_hour = (dosTime>>11) & 0x1f;
1044     localTm.tm_min = (dosTime >> 5) & 0x3f;
1045     localTm.tm_sec = (dosTime & 0x1f) * 2;
1046     localTm.tm_isdst = -1;                              /* compute whether DST in effect */
1047
1048     *unixTimep = mktime(&localTm);
1049 }