2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
19 #define STRSAFE_NO_DEPRECATE
26 #include <afs/unified_afs.h>
28 static osi_once_t cm_utilsOnce;
30 osi_rwlock_t cm_utilsLock;
32 cm_space_t *cm_spaceListp;
34 static int et2sys[512];
36 static DWORD cm_TlsRequestSlot = -1;
38 void cm_utilsInit(void)
40 if (osi_Once(&cm_utilsOnce)) {
41 lock_InitializeRWLock(&cm_utilsLock, "cm_utilsLock", LOCK_HIERARCHY_UTILS_GLOBAL);
43 cm_TlsRequestSlot = TlsAlloc();
45 osi_EndOnce(&cm_utilsOnce);
49 void cm_utilsCleanup(void)
51 TlsFree(cm_TlsRequestSlot);
55 init_et_to_sys_error(void)
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;
184 et_to_sys_error(afs_int32 in)
186 if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512)
188 if (et2sys[in - ERROR_TABLE_BASE_uae] != 0)
189 return et2sys[in - ERROR_TABLE_BASE_uae];
193 long cm_MapRPCError(long error, cm_req_t *reqp)
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;
205 return reqp->rpcError;
209 error = et_to_sys_error(error);
211 if (error == RX_CALL_DEAD ||
212 error == RX_CALL_TIMEOUT)
213 error = CM_ERROR_RETRY;
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
234 error = CM_ERROR_SPACE;
235 else if (error == VOVERQUOTA
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;
254 long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
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;
266 return reqp->rpcError;
270 error = et_to_sys_error(error);
272 if (error == RX_CALL_DEAD ||
273 error == RX_CALL_TIMEOUT ||
274 error == RX_RESTARTING)
275 error = CM_ERROR_RETRY;
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;
295 long cm_MapVLRPCError(long error, cm_req_t *reqp)
297 if (error == 0) return 0;
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;
306 return reqp->rpcError;
310 error = et_to_sys_error(error);
312 if (error == RX_CALL_DEAD ||
313 error == RX_CALL_TIMEOUT ||
314 error == RX_RESTARTING)
315 error = CM_ERROR_RETRY;
317 error = CM_ERROR_UNKNOWN;
318 else if (error == VL_NOENT || error == VL_BADNAME)
319 error = CM_ERROR_NOSUCHVOLUME;
323 cm_space_t *cm_GetSpace(void)
329 lock_ObtainWrite(&cm_utilsLock);
330 if (tsp = cm_spaceListp) {
331 cm_spaceListp = tsp->nextp;
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);
340 void cm_FreeSpace(cm_space_t *tsp)
342 lock_ObtainWrite(&cm_utilsLock);
343 tsp->nextp = cm_spaceListp;
345 lock_ReleaseWrite(&cm_utilsLock);
348 /* characters that are legal in an 8.3 name */
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.
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
375 #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
377 /* return true iff component is a valid 8.3 name */
378 int cm_Is8Dot3(clientchar_t *namep)
384 if (namep == NULL || !namep[0])
388 * can't have a leading dot;
389 * special case for . and ..
391 if (namep[0] == '.') {
394 if (namep[1] == '.' && namep[2] == 0)
398 while (tc = *namep++) {
400 /* saw another dot */
401 if (sawDot) return 0; /* second dot */
406 if (!ISLEGALCHAR(tc))
409 if (!sawDot && charCount > 8)
410 /* more than 8 chars in name */
412 if (sawDot && charCount > 3)
413 /* more than 3 chars in extension */
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.
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', '_', '-', '$', '#', '!', '{', '}'
430 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
432 void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
433 clientchar_t *shortName, clientchar_t **shortNameEndp)
437 int vnode = ntohl(pfid->vnode);
439 int validExtension = 0;
443 /* Unparse the file's vnode number to get a "uniquifier" */
445 number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
447 vnode /= cm_8Dot3MapSize;
451 * Look for valid extension. There has to be a dot, and
452 * at least one of the characters following has to be legal.
454 lastDot = strrchr(longname, '.');
456 temp = lastDot; temp++;
464 /* Copy name characters */
465 for (i = 0, name = longname;
466 i < (7 - nsize) && name != lastDot; ) {
471 if (!ISLEGALCHAR(tc))
474 *shortName++ = toupper(tc);
480 /* Copy uniquifier characters */
481 for (i=0; i < nsize; i++) {
482 *shortName++ = number[i];
485 if (validExtension) {
486 /* Copy extension characters */
487 *shortName++ = *lastDot++; /* copy dot */
488 for (i = 0, tc = *lastDot++;
491 if (ISLEGALCHAR(tc)) {
493 *shortName++ = toupper(tc);
502 *shortNameEndp = shortName;
505 void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
506 clientchar_t *shortName, clientchar_t **shortNameEndp)
508 clientchar_t number[12];
510 int vnode = ntohl(pfid->vnode);
511 clientchar_t *lastDot;
512 int validExtension = 0;
513 clientchar_t tc, *temp;
514 const clientchar_t *name;
516 /* Unparse the file's vnode number to get a "uniquifier" */
518 number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
520 vnode /= cm_8Dot3MapSize;
524 * Look for valid extension. There has to be a dot, and
525 * at least one of the characters following has to be legal.
527 lastDot = cm_ClientStrRChr(longname, '.');
529 temp = lastDot; temp++;
537 /* Copy name characters */
538 for (i = 0, name = longname;
539 i < (7 - nsize) && name != lastDot; ) {
544 if (!ISLEGALCHAR(tc))
547 *shortName++ = toupper((char) tc);
553 /* Copy uniquifier characters */
554 for (i=0; i < nsize; i++) {
555 *shortName++ = number[i];
558 if (validExtension) {
559 /* Copy extension characters */
560 *shortName++ = *lastDot++; /* copy dot */
561 for (i = 0, tc = *lastDot++;
564 if (ISLEGALCHAR(tc)) {
566 *shortName++ = toupper(tc);
575 *shortNameEndp = shortName;
578 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
580 \note This procedure works recursively calling itself.
582 \param[in] pattern string containing metacharacters.
583 \param[in] name File name to be compared with 'pattern'.
585 \return BOOL : TRUE/FALSE (match/mistmatch)
588 szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold)
590 clientchar_t upattern[MAX_PATH];
591 clientchar_t uname[MAX_PATH];
593 clientchar_t * pename; // points to the last 'name' character
595 clientchar_t * pattern_next;
598 cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
599 cm_ClientStrUpr(upattern);
602 cm_ClientStrCpy(uname, lengthof(uname), name);
603 cm_ClientStrUpr(uname);
606 /* The following translations all work on single byte
608 for (p=upattern; *p; p++) {
609 if (*p == '"') *p = '.'; continue;
610 if (*p == '<') *p = '*'; continue;
611 if (*p == '>') *p = '?'; continue;
614 for (p=uname; *p; p++) {
615 if (*p == '"') *p = '.'; continue;
616 if (*p == '<') *p = '*'; continue;
617 if (*p == '>') *p = '?'; continue;
621 pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
626 pattern = cm_ClientCharNext(pattern);
629 name = cm_ClientCharNext(name);
633 pattern = cm_ClientCharNext(pattern);
634 if (*pattern == '\0')
637 pattern_next = cm_ClientCharNext(pattern);
639 for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
640 if (*p == *pattern &&
641 szWildCardMatchFileName(pattern_next,
642 cm_ClientCharNext(p), FALSE))
645 if (*pattern == '.' && *pattern_next == '\0') {
646 for (p = name; p && *p; p = cm_ClientCharNext(p))
656 if (*name != *pattern)
658 pattern = cm_ClientCharNext(pattern);
659 name = cm_ClientCharNext(name);
664 /* if all we have left are wildcards, then we match */
665 for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
666 if (*pattern != '*' && *pattern != '?')
672 /* do a case-folding search of the star name mask with the name in namep.
673 * Return 1 if we match, otherwise 0.
675 int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags)
677 clientchar_t *newmask, lastchar = _C('\0');
678 int i, j, casefold, retval;
679 int star = 0, qmark = 0, dot = 0;
681 /* make sure we only match 8.3 names, if requested */
682 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
685 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
687 /* optimize the pattern:
688 * if there is a mixture of '?' and '*',
689 * for example the sequence "*?*?*?*"
690 * must be turned into the form "*"
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++) {
695 switch ( maskp[i] ) {
710 } else if ( qmark ) {
714 newmask[j++] = maskp[i];
721 } else if ( qmark ) {
725 if (dot == 0 && lastchar == '<')
729 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
736 cm_TargetPerceivedAsDirectory(const fschar_t *target)
740 ext = PathFindExtension(target);
748 cm_LoadAfsdHookLib(void)
754 if (!GetModuleFileName(NULL, dllname, sizeof(dllname)))
757 p = strrchr(dllname, '\\');
760 strcpy(p, AFSD_HOOK_DLL);
761 hLib = LoadLibrary(dllname);
763 hLib = LoadLibrary(AFSD_HOOK_DLL);
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().
775 cm_GetOSFileVersion (char *filename, LARGE_INTEGER *liVer)
783 VS_FIXEDFILEINFO vsf;
785 dwSize = GetFileVersionInfoSizeA(filename,&dwHandle);
790 pInfo = (char*)malloc(dwSize);
795 rc = GetFileVersionInfoA(filename, dwHandle, dwSize, pInfo);
798 rc = VerQueryValueA(pInfo,"\\",&pbuf, &uLen);
801 memcpy(&vsf, pbuf, sizeof(VS_FIXEDFILEINFO));
803 liVer->LowPart = vsf.dwFileVersionLS;
804 liVer->HighPart = vsf.dwFileVersionMS;
813 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
814 typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID *);
815 typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID);
817 BOOL msftSMBRedirectorSupportsExtendedTimeouts(void)
819 static BOOL fChecked = FALSE;
820 static BOOL fSupportsExtendedTimeouts = FALSE;
824 BOOL isWow64 = FALSE;
825 OSVERSIONINFOEX Version;
827 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
828 LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection = NULL;
829 LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection = NULL;
830 PVOID Wow64RedirectionState;
831 LARGE_INTEGER fvFile, fvHotFixMin;
833 h1 = GetModuleHandle("kernel32.dll"); /* no refcount increase */
835 * If we don't find the fnIsWow64Process function then we
836 * are not running in a Wow64 environment
839 (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process");
841 memset (&Version, 0x00, sizeof(Version));
842 Version.dwOSVersionInfoSize = sizeof(Version);
843 GetVersionEx((OSVERSIONINFO *) &Version);
846 * Support is available as hot fixes / service packs on:
853 if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
854 Version.dwMajorVersion >= 5) {
857 if (Version.dwMajorVersion == 5 &&
858 Version.dwMinorVersion == 1) {
860 fvHotFixMin.HighPart = (5 << 16) | 1;
862 switch (Version.wServicePackMajor) {
864 fvHotFixMin.LowPart = (2600 << 16) | 5815;
867 fvHotFixMin.LowPart = (2600 << 16) | 3572;
870 fSupportsExtendedTimeouts = (Version.wServicePackMajor > 3);
875 /* 64-bit XP and Server 2003 */
876 else if (Version.dwMajorVersion == 5 &&
877 Version.dwMinorVersion == 2) {
879 fvHotFixMin.HighPart = (5 << 16) | 2;
881 switch (Version.wServicePackMajor) {
883 fvHotFixMin.LowPart = (3790 << 16) | 4479;
886 fvHotFixMin.LowPart = (3790 << 16) | 3310;
889 fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
894 /* Vista and Server 2008 */
895 else if (Version.dwMajorVersion == 6 &&
896 Version.dwMinorVersion == 0) {
898 fvHotFixMin.HighPart = (6 << 16) | 0;
900 switch (Version.wServicePackMajor) {
902 fvHotFixMin.LowPart = (6002 << 16) | 18005;
905 fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
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;
918 /* If wow64, disable wow64 redirection and preserve the existing state */
919 if (fnIsWow64Process &&
920 fnIsWow64Process(GetCurrentProcess(), &isWow64) &&
922 fnDisableWow64FsRedirection =
923 (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64DisableWow64FsRedirection");
924 fnRevertWow64FsRedirection =
925 (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64RevertWow64FsRedirection");
926 fnDisableWow64FsRedirection(&Wow64RedirectionState);
929 if (cm_GetOSFileVersion("drivers\\mrxsmb.sys", &fvFile) ||
930 (fvFile.QuadPart >= fvHotFixMin.QuadPart))
931 fSupportsExtendedTimeouts = TRUE;
933 /* If wow64, restore the previous redirection state */
934 if (fnIsWow64Process && isWow64) {
935 fnRevertWow64FsRedirection(Wow64RedirectionState);
942 return fSupportsExtendedTimeouts;
945 void cm_ResetServerPriority()
947 void * p = TlsGetValue(cm_TlsRequestSlot);
950 TlsSetValue(cm_TlsRequestSlot, NULL);
951 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
955 void cm_SetRequestStartTime()
957 time_t * tp = TlsGetValue(cm_TlsRequestSlot);
959 tp = malloc(sizeof(time_t));
963 if (!TlsSetValue(cm_TlsRequestSlot, tp))
968 void cm_UpdateServerPriority()
970 time_t *tp = TlsGetValue(cm_TlsRequestSlot);
973 time_t now = osi_Time();
975 /* Give one priority boost for each 15 seconds */
976 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
981 void cm_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
983 // Note that LONGLONG is a 64-bit value
986 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
987 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
988 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
991 void cm_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
993 // Note that LONGLONG is a 64-bit value
996 ll = largeTimep->dwHighDateTime;
998 ll += largeTimep->dwLowDateTime;
1000 ll -= 116444736000000000;
1003 *unixTimep = (DWORD)ll;
1006 void cm_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
1011 struct tm localJunk;
1012 time_t t = unixTime;
1014 ltp = localtime(&t);
1016 /* if we fail, make up something */
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;
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;
1032 void cm_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
1034 unsigned short dosDate;
1035 unsigned short dosTime;
1038 dosDate = (unsigned short) (searchTime & 0xffff);
1039 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
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 */
1049 *unixTimep = mktime(&localTm);