aea0655d2aecf5879b74096ce8eb7e0c28a97bf4
[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 = CM_ERROR_RETRY;
214     else if (error < 0)
215         error = CM_ERROR_UNKNOWN;
216     else if (error == EROFS) 
217         error = CM_ERROR_READONLY;
218     else if (error == EACCES) 
219         error = CM_ERROR_NOACCESS;
220     else if (error == EXDEV) 
221         error = CM_ERROR_CROSSDEVLINK;
222     else if (error == EEXIST) 
223         error = CM_ERROR_EXISTS;
224     else if (error == ENOTDIR) 
225         error = CM_ERROR_NOTDIR;
226     else if (error == ENOENT)
227         error = CM_ERROR_NOSUCHFILE;
228     else if (error == EAGAIN
229              || error == 35        /* EAGAIN, Digital UNIX */
230              || error == WSAEWOULDBLOCK)
231         error = CM_ERROR_WOULDBLOCK;
232     else if (error == VDISKFULL
233               || error == ENOSPC)
234         error = CM_ERROR_SPACE;
235     else if (error == VOVERQUOTA
236               || error == EDQUOT
237               || error == 49    /* EDQUOT on Solaris */
238               || error == 88    /* EDQUOT on AIX */
239               || error == 69    /* EDQUOT on Digital UNIX and HPUX */
240               || error == 122   /* EDQUOT on Linux */
241               || error == 1133) /* EDQUOT on Irix  */
242         error = CM_ERROR_QUOTA;
243     else if (error == VNOVNODE)
244         error = CM_ERROR_BADFD;
245     else if (error == VNOSERVICE || error == VSALVAGE || error == VOFFLINE)
246         error = CM_ERROR_ALLOFFLINE;
247     else if (error == VBUSY || error == VRESTARTING)
248         error = CM_ERROR_ALLBUSY;
249     else if (error == EISDIR)
250         return CM_ERROR_ISDIR;
251     return error;
252 }
253
254 long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
255 {
256     if (error == 0) 
257         return 0;
258
259     /* If we had to stop retrying, report our saved error code. */
260     if (reqp && error == CM_ERROR_TIMEDOUT) {
261         if (reqp->accessError)
262             return reqp->accessError;
263         if (reqp->volumeError)
264             return reqp->volumeError;
265         if (reqp->rpcError)
266             return reqp->rpcError;
267         return error;
268     }
269
270     error = et_to_sys_error(error);
271
272     if (error == RX_CALL_DEAD ||
273         error == RX_CALL_TIMEOUT ||
274         error == RX_RESTARTING)
275         error = CM_ERROR_RETRY;
276     else if (error < 0)
277         error = CM_ERROR_UNKNOWN;
278     else if (error == EROFS) 
279         error = CM_ERROR_READONLY;
280     else if (error == ENOTDIR) 
281         error = CM_ERROR_NOTDIR;
282     else if (error == EACCES) 
283         error = CM_ERROR_NOACCESS;
284     else if (error == ENOENT) 
285         error = CM_ERROR_NOSUCHFILE;
286     else if (error == ENOTEMPTY 
287               || error == 17            /* AIX */
288               || error == 66            /* SunOS 4, Digital UNIX */
289               || error == 93            /* Solaris 2, IRIX */
290               || error == 247)  /* HP/UX */
291         error = CM_ERROR_NOTEMPTY;
292     return error;
293 }       
294
295 long cm_MapVLRPCError(long error, cm_req_t *reqp)
296 {
297     if (error == 0) return 0;
298
299     /* If we had to stop retrying, report our saved error code. */
300     if (reqp && error == CM_ERROR_TIMEDOUT) {
301         if (reqp->accessError)
302             return reqp->accessError;
303         if (reqp->volumeError)
304             return reqp->volumeError;
305         if (reqp->rpcError)
306             return reqp->rpcError;
307         return error;
308     }
309
310     error = et_to_sys_error(error);
311
312     if (error == RX_CALL_DEAD ||
313         error == RX_CALL_TIMEOUT ||
314         error == RX_RESTARTING)
315         error = CM_ERROR_RETRY;
316     else if (error < 0)
317         error = CM_ERROR_UNKNOWN;
318     else if (error == VL_NOENT || error == VL_BADNAME) 
319         error = CM_ERROR_NOSUCHVOLUME;
320     return error;
321 }
322
323 cm_space_t *cm_GetSpace(void)
324 {
325         cm_space_t *tsp;
326
327         cm_utilsInit();
328
329         lock_ObtainWrite(&cm_utilsLock);
330         if (tsp = cm_spaceListp) {
331                 cm_spaceListp = tsp->nextp;
332         }
333         else tsp = (cm_space_t *) malloc(sizeof(cm_space_t));
334         (void) memset(tsp, 0, sizeof(cm_space_t));
335         lock_ReleaseWrite(&cm_utilsLock);
336         
337         return tsp;
338 }
339
340 void cm_FreeSpace(cm_space_t *tsp)
341 {
342         lock_ObtainWrite(&cm_utilsLock);
343         tsp->nextp = cm_spaceListp;
344         cm_spaceListp = tsp;
345         lock_ReleaseWrite(&cm_utilsLock);
346 }
347
348 /* characters that are legal in an 8.3 name */
349 /*
350  * We used to have 1's for all characters from 128 to 254.  But
351  * the NT client behaves better if we create an 8.3 name for any
352  * name that has a character with the high bit on, and if we
353  * delete those characters from 8.3 names.  In particular, see
354  * Sybase defect 10859.
355  */
356 char cm_LegalChars[256] = {
357  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
359  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
360  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
361  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
362  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
363  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
364  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
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  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
373 };
374
375 #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
376
377 /* return true iff component is a valid 8.3 name */
378 int cm_Is8Dot3(clientchar_t *namep)
379 {
380     int sawDot = 0;
381     clientchar_t tc;
382     int charCount = 0;
383     
384     if (namep == NULL || !namep[0])
385         return 0;
386
387     /*
388      * can't have a leading dot;
389      * special case for . and ..
390      */
391     if (namep[0] == '.') {
392         if (namep[1] == 0)
393             return 1;
394         if (namep[1] == '.' && namep[2] == 0)
395             return 1;
396         return 0;
397     }
398     while (tc = *namep++) {
399         if (tc == '.') {
400             /* saw another dot */
401             if (sawDot) return 0;       /* second dot */
402             sawDot = 1;
403             charCount = 0;
404             continue;
405         }
406         if (!ISLEGALCHAR(tc))
407             return 0;
408         charCount++;
409         if (!sawDot && charCount > 8)
410             /* more than 8 chars in name */
411             return 0;
412         if (sawDot && charCount > 3)
413             /* more than 3 chars in extension */
414             return 0;
415     }
416     return 1;
417 }
418
419 /*
420  * Number unparsing map for generating 8.3 names;
421  * The version taken from DFS was on drugs.  
422  * You can't include '&' and '@' in a file name.
423  */
424 char cm_8Dot3Mapping[42] =
425 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
426  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
427  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
428  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '{', '}'
429 };
430 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
431
432 void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
433                         clientchar_t *shortName, clientchar_t **shortNameEndp)
434 {
435     char number[12];
436     int i, nsize = 0;
437     int vnode = ntohl(pfid->vnode);
438     char *lastDot;
439     int validExtension = 0;
440     char tc, *temp;
441     const char *name;
442
443     /* Unparse the file's vnode number to get a "uniquifier" */
444     do {
445         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
446         nsize++;
447         vnode /= cm_8Dot3MapSize;
448     } while (vnode);
449
450     /*
451      * Look for valid extension.  There has to be a dot, and
452      * at least one of the characters following has to be legal.
453      */
454     lastDot = strrchr(longname, '.');
455     if (lastDot) {
456         temp = lastDot; temp++;
457         while (tc = *temp++)
458             if (ISLEGALCHAR(tc))
459                 break;
460         if (tc)
461             validExtension = 1;
462     }
463
464     /* Copy name characters */
465     for (i = 0, name = longname;
466           i < (7 - nsize) && name != lastDot; ) {
467         tc = *name++;
468
469         if (tc == 0)
470             break;
471         if (!ISLEGALCHAR(tc))
472             continue;
473         i++;
474         *shortName++ = toupper(tc);
475     }
476
477     /* tilde */
478     *shortName++ = '~';
479
480     /* Copy uniquifier characters */
481     for (i=0; i < nsize; i++) {
482         *shortName++ = number[i];
483     }
484
485     if (validExtension) {
486         /* Copy extension characters */
487         *shortName++ = *lastDot++;      /* copy dot */
488         for (i = 0, tc = *lastDot++;
489              i < 3 && tc;
490              tc = *lastDot++) {
491             if (ISLEGALCHAR(tc)) {
492                 i++;
493                 *shortName++ = toupper(tc);
494             }
495         }
496     }
497
498     /* Trailing null */
499     *shortName = 0;
500
501     if (shortNameEndp)
502         *shortNameEndp = shortName;
503 }
504
505 void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
506                          clientchar_t *shortName, clientchar_t **shortNameEndp)
507 {
508     clientchar_t number[12];
509     int i, nsize = 0;
510     int vnode = ntohl(pfid->vnode);
511     clientchar_t *lastDot;
512     int validExtension = 0;
513     clientchar_t tc, *temp;
514     const clientchar_t *name;
515
516     /* Unparse the file's vnode number to get a "uniquifier" */
517     do {
518         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
519         nsize++;
520         vnode /= cm_8Dot3MapSize;
521     } while (vnode);
522
523     /*
524      * Look for valid extension.  There has to be a dot, and
525      * at least one of the characters following has to be legal.
526      */
527     lastDot = cm_ClientStrRChr(longname, '.');
528     if (lastDot) {
529         temp = lastDot; temp++;
530         while (tc = *temp++)
531             if (ISLEGALCHAR(tc))
532                 break;
533         if (tc)
534             validExtension = 1;
535     }
536
537     /* Copy name characters */
538     for (i = 0, name = longname;
539           i < (7 - nsize) && name != lastDot; ) {
540         tc = *name++;
541
542         if (tc == 0)
543             break;
544         if (!ISLEGALCHAR(tc))
545             continue;
546         i++;
547         *shortName++ = toupper((char) tc);
548     }
549
550     /* tilde */
551     *shortName++ = '~';
552
553     /* Copy uniquifier characters */
554     for (i=0; i < nsize; i++) {
555         *shortName++ = number[i];
556     }
557
558     if (validExtension) {
559         /* Copy extension characters */
560         *shortName++ = *lastDot++;      /* copy dot */
561         for (i = 0, tc = *lastDot++;
562              i < 3 && tc;
563              tc = *lastDot++) {
564             if (ISLEGALCHAR(tc)) {
565                 i++;
566                 *shortName++ = toupper(tc);
567             }
568         }
569     }
570
571     /* Trailing null */
572     *shortName = 0;
573
574     if (shortNameEndp)
575         *shortNameEndp = shortName;
576 }
577
578 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
579
580   \note This procedure works recursively calling itself.
581
582   \param[in] pattern string containing metacharacters.
583   \param[in] name File name to be compared with 'pattern'.
584
585   \return BOOL : TRUE/FALSE (match/mistmatch)
586 */
587 static BOOL 
588 szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold) 
589 {
590     clientchar_t upattern[MAX_PATH];
591     clientchar_t uname[MAX_PATH];
592
593     clientchar_t * pename;         // points to the last 'name' character
594     clientchar_t * p;
595     clientchar_t * pattern_next;
596
597     if (casefold) {
598         cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
599         cm_ClientStrUpr(upattern);
600         pattern = upattern;
601
602         cm_ClientStrCpy(uname, lengthof(uname), name);
603         cm_ClientStrUpr(uname);
604         name = uname;
605
606         /* The following translations all work on single byte
607            characters */
608         for (p=upattern; *p; p++) {
609             if (*p == '"') *p = '.'; continue;
610             if (*p == '<') *p = '*'; continue;
611             if (*p == '>') *p = '?'; continue;
612         }
613
614         for (p=uname; *p; p++) {
615             if (*p == '"') *p = '.'; continue;
616             if (*p == '<') *p = '*'; continue;
617             if (*p == '>') *p = '?'; continue;
618         }
619     }
620
621     pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
622
623     while (*name) {
624         switch (*pattern) {
625         case '?':
626             pattern = cm_ClientCharNext(pattern);
627             if (*name == '.')
628                 continue;
629             name = cm_ClientCharNext(name);
630             break;
631
632          case '*':
633             pattern = cm_ClientCharNext(pattern);
634             if (*pattern == '\0')
635                 return TRUE;
636
637             pattern_next = cm_ClientCharNext(pattern);
638
639             for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
640                 if (*p == *pattern &&
641                     szWildCardMatchFileName(pattern_next,
642                                             cm_ClientCharNext(p), FALSE))
643                     return TRUE;
644             } /* endfor */
645             if (*pattern == '.' && *pattern_next == '\0') {
646                 for (p = name; p && *p; p = cm_ClientCharNext(p))
647                     if (*p == '.')
648                         break;
649                 if (p && *p)
650                     return FALSE;
651                 return TRUE;
652             }
653             return FALSE;
654
655         default:
656             if (*name != *pattern)
657                 return FALSE;
658             pattern = cm_ClientCharNext(pattern);
659             name = cm_ClientCharNext(name);
660             break;
661         } /* endswitch */
662     } /* endwhile */
663
664     /* if all we have left are wildcards, then we match */
665     for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
666         if (*pattern != '*' && *pattern != '?')
667             return FALSE;
668     }
669     return TRUE;
670 }
671
672 /* do a case-folding search of the star name mask with the name in namep.
673  * Return 1 if we match, otherwise 0.
674  */
675 int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
676 {
677     clientchar_t *newmask, lastchar = _C('\0');
678     int    i, j, casefold, retval;
679     int  star = 0, qmark = 0, dot = 0;
680
681     /* make sure we only match 8.3 names, if requested */
682     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
683         return 0;
684
685     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
686
687     /* optimize the pattern:
688      * if there is a mixture of '?' and '*',
689      * for example  the sequence "*?*?*?*"
690      * must be turned into the form "*"
691      */
692     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+2)*sizeof(clientchar_t));
693     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
694         lastchar = maskp[i];
695         switch ( maskp[i] ) {
696         case '?':
697         case '>':
698             qmark++;
699             break;
700         case '<':
701         case '*':
702             star++;
703             break;
704         case '.':
705             dot++;
706             /* fallthrough */
707         default:
708             if ( star ) {
709                 newmask[j++] = '*';
710             } else if ( qmark ) {
711                 while ( qmark-- )
712                     newmask[j++] = '?';
713             }
714             newmask[j++] = maskp[i];
715             star = 0;
716             qmark = 0;
717         }
718     }
719     if ( star ) {
720         newmask[j++] = '*';
721     } else if ( qmark ) {
722         while ( qmark-- )
723             newmask[j++] = '?';
724     }
725     if (dot == 0 && lastchar == '<')
726         newmask[j++] = '.';
727     newmask[j++] = '\0';
728
729     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
730
731     free(newmask);
732     return retval;
733 }
734
735 BOOL
736 cm_TargetPerceivedAsDirectory(const fschar_t *target)
737 {
738     char        * ext;
739
740     ext = PathFindExtension(target);
741     if (!ext[0])
742         return TRUE;
743
744     return FALSE;
745 }
746
747 HANDLE 
748 cm_LoadAfsdHookLib(void)
749 {
750     char dllname[260];
751     char *p;
752     HANDLE hLib;
753
754     if (!GetModuleFileName(NULL, dllname, sizeof(dllname)))
755         return NULL;
756
757     p = strrchr(dllname, '\\');
758     if (p) {
759         p++;
760         strcpy(p, AFSD_HOOK_DLL);
761         hLib = LoadLibrary(dllname);
762     } else {
763         hLib = LoadLibrary(AFSD_HOOK_DLL);
764     }
765
766     return hLib;
767 }
768
769 /*
770  * Obtain the file info structure for the specified file.
771  * If a full path is not specified, the search order is the
772  * same as that used by LoadLibrary().
773  */
774 BOOL
775 cm_GetOSFileVersion (char *filename, LARGE_INTEGER *liVer)
776 {
777     DWORD dwHandle;
778     DWORD dwSize;
779     char* pInfo = NULL;
780     BOOL  rc;
781     UINT uLen;
782     void *pbuf;
783     VS_FIXEDFILEINFO vsf;
784
785     dwSize = GetFileVersionInfoSizeA(filename,&dwHandle);
786     if (dwSize == 0) {
787         rc = FALSE;
788         goto done;
789     }
790     pInfo = (char*)malloc(dwSize);
791     if (!pInfo) {
792         rc = FALSE;
793         goto done;
794     }
795     rc = GetFileVersionInfoA(filename, dwHandle, dwSize, pInfo);
796     if (!rc)
797         goto done;
798     rc = VerQueryValueA(pInfo,"\\",&pbuf, &uLen);
799     if (!rc)
800         goto done;
801     memcpy(&vsf, pbuf, sizeof(VS_FIXEDFILEINFO));
802
803     liVer->LowPart = vsf.dwFileVersionLS;
804     liVer->HighPart = vsf.dwFileVersionMS;
805     rc = TRUE;
806
807   done:
808     if (pInfo)
809         free(pInfo);
810     return rc;
811 }
812
813 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
814 typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID *);
815 typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID);
816
817 BOOL msftSMBRedirectorSupportsExtendedTimeouts(void) 
818 {
819     static BOOL fChecked = FALSE;
820     static BOOL fSupportsExtendedTimeouts = FALSE;
821
822     if (!fChecked)
823     {
824         BOOL isWow64 = FALSE;
825         OSVERSIONINFOEX Version;
826         HANDLE h1 = NULL;
827         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
828         LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection = NULL;
829         LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection = NULL;
830         PVOID Wow64RedirectionState;
831         LARGE_INTEGER fvFile, fvHotFixMin;
832
833         h1 = GetModuleHandle("kernel32.dll"); /* no refcount increase */
834         /* 
835          * If we don't find the fnIsWow64Process function then we
836          * are not running in a Wow64 environment
837          */
838         fnIsWow64Process =
839             (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process");
840
841         memset (&Version, 0x00, sizeof(Version));
842         Version.dwOSVersionInfoSize = sizeof(Version);
843         GetVersionEx((OSVERSIONINFO *) &Version);
844
845         /* 
846          * Support is available as hot fixes / service packs on:
847          *   XP SP2
848          *   XP SP3
849          *   2003 and XP64 SP2
850          *   Vista and 2008 SP2
851          *   Win7 and 2008 R2
852          */
853         if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
854             Version.dwMajorVersion >= 5) {
855
856             /* 32-bit XP */
857             if (Version.dwMajorVersion == 5 &&
858                 Version.dwMinorVersion == 1) {
859                 
860                 fvHotFixMin.HighPart = (5 << 16) | 1;
861
862                 switch (Version.wServicePackMajor) {
863                 case 3:
864                     fvHotFixMin.LowPart = (2600 << 16) | 5815;
865                     break;
866                 case 2:
867                     fvHotFixMin.LowPart = (2600 << 16) | 3572;
868                     break;
869                 default:
870                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 3);
871                     goto checked;
872                 }
873             }
874
875             /* 64-bit XP and Server 2003 */
876             else if (Version.dwMajorVersion == 5 &&
877                      Version.dwMinorVersion == 2) {
878                 
879                 fvHotFixMin.HighPart = (5 << 16) | 2;
880
881                 switch (Version.wServicePackMajor) {
882                 case 2:
883                     fvHotFixMin.LowPart = (3790 << 16) | 4479;
884                     break;
885                 case 1:
886                     fvHotFixMin.LowPart = (3790 << 16) | 3310;
887                     break;
888                 default:
889                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
890                     goto checked;
891                 }
892             }
893
894             /* Vista and Server 2008 */
895             else if (Version.dwMajorVersion == 6 &&
896                      Version.dwMinorVersion == 0) {
897                 
898                 fvHotFixMin.HighPart = (6 << 16) | 0;
899
900                 switch (Version.wServicePackMajor) {
901                 case 2:
902                     fvHotFixMin.LowPart = (6002 << 16) | 18005;
903                     break;
904                 default:
905                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
906                     goto checked;
907                 }
908             }
909
910             /* Windows 7 and Server 2008 R2 and beyond */
911             else if (Version.dwMajorVersion > 6 ||
912                      Version.dwMajorVersion == 6 &&
913                      Version.dwMinorVersion >= 1) {
914                 fSupportsExtendedTimeouts = TRUE;
915                 goto checked;
916             }
917
918             /* If wow64, disable wow64 redirection and preserve the existing state */
919             if (fnIsWow64Process && 
920                  fnIsWow64Process(GetCurrentProcess(), &isWow64) &&
921                  isWow64) {
922                 fnDisableWow64FsRedirection =
923                     (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64DisableWow64FsRedirection");
924                 fnRevertWow64FsRedirection =
925                     (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64RevertWow64FsRedirection");
926                 fnDisableWow64FsRedirection(&Wow64RedirectionState);
927             }
928             
929             if (cm_GetOSFileVersion("drivers\\mrxsmb.sys", &fvFile) ||
930                 (fvFile.QuadPart >= fvHotFixMin.QuadPart))
931                 fSupportsExtendedTimeouts = TRUE;
932
933             /* If wow64, restore the previous redirection state */
934             if (fnIsWow64Process && isWow64) {
935                 fnRevertWow64FsRedirection(Wow64RedirectionState);
936             }            
937         }
938       checked:
939         fChecked = TRUE;
940     }
941
942     return fSupportsExtendedTimeouts;
943 }
944
945 void cm_ResetServerPriority()
946 {
947     void * p = TlsGetValue(cm_TlsRequestSlot);
948     if (p) {
949         free(p);
950         TlsSetValue(cm_TlsRequestSlot, NULL);
951         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
952     }
953 }
954
955 void cm_SetRequestStartTime()
956 {
957     time_t * tp = TlsGetValue(cm_TlsRequestSlot);
958     if (!tp)
959         tp = malloc(sizeof(time_t));
960     if (tp) {
961         *tp = osi_Time();
962
963         if (!TlsSetValue(cm_TlsRequestSlot, tp))
964             free(tp);
965     }   
966 }
967
968 void cm_UpdateServerPriority()
969 {       
970     time_t *tp = TlsGetValue(cm_TlsRequestSlot);
971
972     if (tp) {
973         time_t now = osi_Time();
974
975         /* Give one priority boost for each 15 seconds */
976         SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
977     }
978 }
979
980
981 void cm_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
982 {
983     // Note that LONGLONG is a 64-bit value
984     LONGLONG ll;
985
986     ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
987     largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
988     largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
989 }
990
991 void cm_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
992 {
993     // Note that LONGLONG is a 64-bit value
994     LONGLONG ll;
995
996     ll = largeTimep->dwHighDateTime;
997     ll <<= 32;
998     ll += largeTimep->dwLowDateTime;
999
1000     ll -= 116444736000000000;
1001     ll /= 10000000;
1002
1003     *unixTimep = (DWORD)ll;
1004 }
1005
1006 void cm_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
1007 {
1008     struct tm *ltp;
1009     int dosDate;
1010     int dosTime;
1011     struct tm localJunk;
1012     time_t t = unixTime;
1013
1014     ltp = localtime(&t);
1015
1016     /* if we fail, make up something */
1017     if (!ltp) {
1018         ltp = &localJunk;
1019         localJunk.tm_year = 89 - 20;
1020         localJunk.tm_mon = 4;
1021         localJunk.tm_mday = 12;
1022         localJunk.tm_hour = 0;
1023         localJunk.tm_min = 0;
1024         localJunk.tm_sec = 0;
1025     }   
1026
1027     dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
1028     dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
1029     *searchTimep = (dosDate<<16) | dosTime;
1030 }       
1031
1032 void cm_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
1033 {
1034     unsigned short dosDate;
1035     unsigned short dosTime;
1036     struct tm localTm;
1037         
1038     dosDate = (unsigned short) (searchTime & 0xffff);
1039     dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
1040
1041     localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
1042     localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;        /* January is 0 in localTm */
1043     localTm.tm_mday = (dosDate) & 0x1f;
1044     localTm.tm_hour = (dosTime>>11) & 0x1f;
1045     localTm.tm_min = (dosTime >> 5) & 0x3f;
1046     localTm.tm_sec = (dosTime & 0x1f) * 2;
1047     localTm.tm_isdst = -1;                              /* compute whether DST in effect */
1048
1049     *unixTimep = mktime(&localTm);
1050 }