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