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