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