Whamcloud - gitweb
e34e744ca5e71c40a987d477059c5250f98a3826
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-utils.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=4:tabstop=4:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37
38 /*
39  * miscellaneous libcfs stuff
40  */
41 #define DEBUG_SUBSYSTEM S_LNET
42 #include <libcfs/libcfs.h>
43 #include <errno.h>
44
45 /*
46  *  IDR support routines
47  *
48  *  local global id <-> handle context
49  */
50
51 /* idr definitions */
52
53 #define IDR_BITS 7
54 #define IDR_FULL 0xffffffff
55 #define IDR_SIZE (1 << IDR_BITS)
56 #define IDR_MASK ((1 << IDR_BITS)-1)
57 #define MAX_ID_SHIFT (sizeof(int)*8 - 1)
58 #define MAX_ID_BIT (1U << MAX_ID_SHIFT)
59 #define MAX_ID_MASK (MAX_ID_BIT - 1)
60 #define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
61 #define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
62
63 #define idr_set_bit(bit, v) (v) |= (1<<(bit))
64 #define idr_clear_bit(bit, v) (v) &= ~(1<<(bit))
65 #define idr_test_bit(bit, v) ((v) & (1<<(bit)))
66
67 struct idr_layer {
68         uint32_t            bitmap;
69         struct idr_layer   *ary[IDR_SIZE];
70         int                             count;
71 };
72
73 struct idr_context {
74         struct idr_layer *top;
75         struct idr_layer *id_free;
76         int               layers;
77         int               id_free_cnt;
78 };
79
80
81 /*
82  * id (fd) <-> pointer (HANDLE)
83  */
84
85 /**********************************************************
86   private structures and routines for id implementation
87 ***********************************************************/
88                                    
89 static struct idr_layer *alloc_layer(struct idr_context *idp)
90 {
91         struct idr_layer *p;
92
93         if (!(p = idp->id_free))
94                 return NULL;
95         idp->id_free = p->ary[0];
96         idp->id_free_cnt--;
97         p->ary[0] = NULL;
98         return p;
99 }
100
101 static int find_next_idrbit(uint32_t bm, int maxid, int n)
102 {
103         while (n<maxid && !idr_test_bit(n, bm)) n++;
104         return n;
105 }
106
107 static void free_layer(struct idr_context *idp, struct idr_layer *p)
108 {
109         p->ary[0] = idp->id_free;
110         idp->id_free = p;
111         idp->id_free_cnt++;
112 }
113
114 static int idr_pre_get(struct idr_context *idp)
115 {
116         while (idp->id_free_cnt < IDR_FREE_MAX) {
117                 struct idr_layer *new;
118
119         new = cfs_alloc(sizeof(struct idr_layer), CFS_ALLOC_ZERO);
120                 if(new == NULL)
121                         return (0);
122                 free_layer(idp, new);
123         }
124         return 1;
125 }
126
127 static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
128 {
129         int n, m, sh;
130         struct idr_layer *p, *new;
131         struct idr_layer *pa[MAX_LEVEL];
132         int l, id;
133         uint32_t bm;
134
135         memset(pa, 0, sizeof(pa));
136
137         id = *starting_id;
138         p = idp->top;
139         l = idp->layers;
140         pa[l--] = NULL;
141         while (1) {
142                 /*
143                  * We run around this while until we reach the leaf node...
144                  */
145                 n = (id >> (IDR_BITS*l)) & IDR_MASK;
146                 bm = ~p->bitmap;
147                 m = find_next_idrbit(bm, IDR_SIZE, n);
148                 if (m == IDR_SIZE) {
149                         /* no space available go back to previous layer. */
150                         l++;
151                         id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
152                         if (!(p = pa[l])) {
153                                 *starting_id = id;
154                                 return -2;
155                         }
156                         continue;
157                 }
158                 if (m != n) {
159                         sh = IDR_BITS*l;
160                         id = ((id >> sh) ^ n ^ m) << sh;
161                 }
162                 if ((id >= MAX_ID_BIT) || (id < 0))
163                         return -1;
164                 if (l == 0)
165                         break;
166                 /*
167                  * Create the layer below if it is missing.
168                  */
169                 if (!p->ary[m]) {
170                         if (!(new = alloc_layer(idp)))
171                                 return -1;
172                         p->ary[m] = new;
173                         p->count++;
174                 }
175                 pa[l--] = p;
176                 p = p->ary[m];
177         }
178         /*
179          * We have reached the leaf node, plant the
180          * users pointer and return the raw id.
181          */
182         p->ary[m] = (struct idr_layer *)ptr;
183         idr_set_bit(m, p->bitmap);
184         p->count++;
185         /*
186          * If this layer is full mark the bit in the layer above
187          * to show that this part of the radix tree is full.
188          * This may complete the layer above and require walking
189          * up the radix tree.
190          */
191         n = id;
192         while (p->bitmap == IDR_FULL) {
193                 if (!(p = pa[++l]))
194                         break;
195                 n = n >> IDR_BITS;
196                 idr_set_bit((n & IDR_MASK), p->bitmap);
197         }
198         return(id);
199 }
200
201 static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id)
202 {
203         struct idr_layer *p, *new;
204         int layers, v, id;
205
206         idr_pre_get(idp);
207         
208         id = starting_id;
209 build_up:
210         p = idp->top;
211         layers = idp->layers;
212         if (!p) {
213                 if (!(p = alloc_layer(idp)))
214                         return -1;
215                 layers = 1;
216         }
217         /*
218          * Add a new layer to the top of the tree if the requested
219          * id is larger than the currently allocated space.
220          */
221         while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
222                 layers++;
223                 if (!p->count)
224                         continue;
225                 if (!(new = alloc_layer(idp))) {
226                         /*
227                          * The allocation failed.  If we built part of
228                          * the structure tear it down.
229                          */
230                         for (new = p; p && p != idp->top; new = p) {
231                                 p = p->ary[0];
232                                 new->ary[0] = NULL;
233                                 new->bitmap = new->count = 0;
234                                 free_layer(idp, new);
235                         }
236                         return -1;
237                 }
238                 new->ary[0] = p;
239                 new->count = 1;
240                 if (p->bitmap == IDR_FULL)
241                         idr_set_bit(0, new->bitmap);
242                 p = new;
243         }
244         idp->top = p;
245         idp->layers = layers;
246         v = sub_alloc(idp, ptr, &id);
247         if (v == -2)
248                 goto build_up;
249         return(v);
250 }
251
252 static int sub_remove(struct idr_context *idp, int shift, int id)
253 {
254         struct idr_layer *p = idp->top;
255         struct idr_layer **pa[MAX_LEVEL];
256         struct idr_layer ***paa = &pa[0];
257         int n;
258
259         *paa = NULL;
260         *++paa = &idp->top;
261
262         while ((shift > 0) && p) {
263                 n = (id >> shift) & IDR_MASK;
264                 idr_clear_bit(n, p->bitmap);
265                 *++paa = &p->ary[n];
266                 p = p->ary[n];
267                 shift -= IDR_BITS;
268         }
269         n = id & IDR_MASK;
270         if (p != NULL && idr_test_bit(n, p->bitmap)) {
271                 idr_clear_bit(n, p->bitmap);
272                 p->ary[n] = NULL;
273                 while(*paa && ! --((**paa)->count)){
274                         free_layer(idp, **paa);
275                         **paa-- = NULL;
276                 }
277                 if ( ! *paa )
278                         idp->layers = 0;
279                 return 0;
280         }
281         return -1;
282 }
283
284 static void *_idr_find(struct idr_context *idp, int id)
285 {
286         int n;
287         struct idr_layer *p;
288
289         n = idp->layers * IDR_BITS;
290         p = idp->top;
291         /*
292          * This tests to see if bits outside the current tree are
293          * present.  If so, tain't one of ours!
294          */
295         if ((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))
296              return NULL;
297
298         /* Mask off upper bits we don't use for the search. */
299         id &= MAX_ID_MASK;
300
301         while (n >= IDR_BITS && p) {
302                 n -= IDR_BITS;
303                 p = p->ary[(id >> n) & IDR_MASK];
304         }
305         return((void *)p);
306 }
307
308 static int _idr_remove(struct idr_context *idp, int id)
309 {
310         struct idr_layer *p;
311
312         /* Mask off upper bits we don't use for the search. */
313         id &= MAX_ID_MASK;
314
315         if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) {
316                 return -1;
317         }
318
319         if ( idp->top && idp->top->count == 1 && 
320              (idp->layers > 1) &&
321              idp->top->ary[0]) {
322                 /* We can drop a layer */
323                 p = idp->top->ary[0];
324                 idp->top->bitmap = idp->top->count = 0;
325                 free_layer(idp, idp->top);
326                 idp->top = p;
327                 --idp->layers;
328         }
329         while (idp->id_free_cnt >= IDR_FREE_MAX) {
330                 p = alloc_layer(idp);
331                 cfs_free(p);
332         }
333         return 0;
334 }
335
336 /**********************************************************
337   publick interfaces of id vs handle conversion
338 ***********************************************************/
339
340 /**
341   initialise a idr tree.
342  */
343 struct idr_context *cfs_idr_init()
344 {
345     struct idr_context * idp = NULL;
346     idp = cfs_alloc(sizeof(struct idr_context), 0);
347     if (idp) {
348         memset(idp, 0, sizeof(struct idr_context));
349     }
350
351     return idp;
352 }
353
354 /**
355   remove an id from the idr tree
356 */
357 int cfs_idr_remove(struct idr_context *idp, int id)
358 {
359         int ret;
360         ret = _idr_remove((struct idr_context *)idp, id);
361         if (ret != 0) {
362                 CWARN("WARNING: attempt to remove unset id %d in idtree\n", id);
363         }
364         return ret;
365 }
366
367 /**
368   allocate the next available id, and assign 'ptr' into its slot.
369   you can retrieve later this pointer using idr_find()
370 */
371 int cfs_idr_get_new(struct idr_context *idp, void *ptr)
372 {
373         int ret = idr_get_new_above_int(idp, ptr, 0);
374         if (ret > MAX_ID_MASK) {
375                 cfs_idr_remove(idp, ret);
376                 return -1;
377         }
378         return ret;
379 }
380
381 /**
382    allocate a new id, giving the first available value greater than or
383    equal to the given starting id
384 */
385 int cfs_idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id)
386 {
387         int ret = idr_get_new_above_int(idp, ptr, starting_id);
388         if (ret > MAX_ID_MASK) {
389                 cfs_idr_remove(idp, ret);
390                 return -1;
391         }
392         return ret;
393 }
394
395 /**
396   find a pointer value previously set with idr_get_new given an id
397 */
398 void *cfs_idr_find(struct idr_context *idp, int id)
399 {
400         return _idr_find(idp, id);
401 }
402
403 /**
404   destroy a idr tree. 
405  */
406 void cfs_idr_exit(struct idr_context *idp)
407 {
408     if (idp) {
409             cfs_free(idp);
410     }
411 }
412
413 /*
414  * convert <fcntl.h> flag from client to server.
415  * 
416  * nt kernel uses several members to describe the open flags
417  * such as DesiredAccess/ShareAccess/CreateDisposition/CreateOptions
418  * so it's better to convert when using, not here.
419  */
420
421 int convert_client_oflag(int cflag, int *result)
422 {
423     *result = 0;
424         return 0;
425 }
426
427 int cfs_error_code(NTSTATUS Status)
428 {
429     switch (Status) {
430
431         case STATUS_ACCESS_DENIED:
432             return (-EACCES);
433
434         case STATUS_ACCESS_VIOLATION:
435             return (-EFAULT);
436     
437         case STATUS_BUFFER_TOO_SMALL:
438             return (-ETOOSMALL);
439
440         case STATUS_INVALID_PARAMETER:
441             return (-EINVAL);
442
443         case STATUS_NOT_IMPLEMENTED:
444         case STATUS_NOT_SUPPORTED:
445             return (-EOPNOTSUPP);
446
447         case STATUS_INVALID_ADDRESS:
448         case STATUS_INVALID_ADDRESS_COMPONENT:
449             return (-EADDRNOTAVAIL);
450
451         case STATUS_NO_SUCH_DEVICE:
452         case STATUS_NO_SUCH_FILE:
453         case STATUS_OBJECT_NAME_NOT_FOUND:
454         case STATUS_OBJECT_PATH_NOT_FOUND:  
455         case STATUS_NETWORK_BUSY:
456         case STATUS_INVALID_NETWORK_RESPONSE:
457         case STATUS_UNEXPECTED_NETWORK_ERROR:
458             return (-ENETDOWN);
459
460         case STATUS_BAD_NETWORK_PATH:
461         case STATUS_NETWORK_UNREACHABLE:
462         case STATUS_PROTOCOL_UNREACHABLE:     
463             return (-ENETUNREACH);
464
465         case STATUS_LOCAL_DISCONNECT:
466         case STATUS_TRANSACTION_ABORTED:
467         case STATUS_CONNECTION_ABORTED:
468             return (-ECONNABORTED);
469
470         case STATUS_REMOTE_DISCONNECT:
471         case STATUS_LINK_FAILED:
472         case STATUS_CONNECTION_DISCONNECTED:
473         case STATUS_CONNECTION_RESET:
474         case STATUS_PORT_UNREACHABLE:
475             return (-ECONNRESET);
476
477         case STATUS_INSUFFICIENT_RESOURCES:
478             return (-ENOMEM);
479
480         case STATUS_PAGEFILE_QUOTA:
481         case STATUS_NO_MEMORY:
482         case STATUS_CONFLICTING_ADDRESSES:
483         case STATUS_QUOTA_EXCEEDED:
484         case STATUS_TOO_MANY_PAGING_FILES:
485         case STATUS_WORKING_SET_QUOTA:
486         case STATUS_COMMITMENT_LIMIT:
487         case STATUS_TOO_MANY_ADDRESSES:
488         case STATUS_REMOTE_RESOURCES:
489             return (-ENOBUFS);
490
491         case STATUS_INVALID_CONNECTION:
492             return (-ENOTCONN);
493
494         case STATUS_PIPE_DISCONNECTED:
495             return (-ESHUTDOWN);
496
497         case STATUS_TIMEOUT:
498         case STATUS_IO_TIMEOUT:
499         case STATUS_LINK_TIMEOUT:
500             return (-ETIMEDOUT);
501
502         case STATUS_REMOTE_NOT_LISTENING:
503         case STATUS_CONNECTION_REFUSED:
504             return (-ECONNREFUSED);
505
506         case STATUS_HOST_UNREACHABLE:
507             return (-EHOSTUNREACH);
508
509         case STATUS_PENDING:
510         case STATUS_DEVICE_NOT_READY:
511             return (-EAGAIN);
512
513         case STATUS_CANCELLED:
514         case STATUS_REQUEST_ABORTED:
515             return (-EINTR);
516
517         case STATUS_BUFFER_OVERFLOW:
518         case STATUS_INVALID_BUFFER_SIZE:
519             return (-EMSGSIZE);
520
521         case STATUS_ADDRESS_ALREADY_EXISTS:
522             return (-EADDRINUSE);
523     }
524
525     if (NT_SUCCESS(Status)) 
526         return 0;
527
528     return (-EINVAL);
529 }
530
531 /*
532  * Convert server error code to client format. Error codes are from
533  * Linux errno.h, so for Linux client---identity.
534  */
535 int convert_server_error(__u64 ecode)
536 {
537         return cfs_error_code((NTSTATUS)ecode);
538 }
539
540 char * strsep(char **strp, const char *delim)
541 {
542     char *begin, *end;
543
544     begin = *strp;
545     if (begin == NULL) {
546         return NULL;
547     }
548
549     if (delim[0] == '\0' || delim[1] == '\0') {
550         char ch = delim[0];
551         if (ch == '\0') {
552                 end = NULL;
553         } else {
554                 if (*begin == ch) {
555                     end = begin;
556                 } else if (*begin == '\0') {
557                     end = NULL;
558                 } else {
559                     end = strchr (begin + 1, ch);
560                 }
561         }
562     } else {
563         end = strpbrk (begin, delim);
564     }
565
566     if (end) {
567         *end++ = '\0';
568         *strp = end;
569     } else {
570         *strp = NULL;
571     }
572
573     return begin;
574 }
575
576 /*
577  * strnchr - Find a character in a length limited string
578  * @s: The string to be searched
579  * @count: The number of characters to be searched
580  * @c: The character to search for
581  */
582
583 char *strnchr(const char *s, size_t count, int c)
584 {
585     for (; count-- && *s != '\0'; ++s)
586         if (*s == (char) c)
587             return (char *) s;
588     return NULL;
589 }
590
591 __u64 strtoull(char *nptr, char **endptr,int base)
592 {
593         char *s = nptr;
594         __u64 acc, cutoff;
595         int c, neg = 0, any, cutlim;
596
597         /*
598          * See strtol for comments as to the logic used.
599          */
600         do {
601                 c = *s++;
602         } while (cfs_isspace(c));
603         if (c == '-') {
604                 neg = 1;
605                 c = *s++;
606         } else if (c == '+')
607                 c = *s++;
608         if ((base == 0 || base == 16) &&
609             c == '0' && (*s == 'x' || *s == 'X')) {
610                 c = s[1];
611                 s += 2;
612                 base = 16;
613         }
614         if (base == 0)
615                 base = c == '0' ? 8 : 10;
616         cutoff = (__u64)ULONG_LONG_MAX / (__u64)base;
617         cutlim = (int)((__u64)ULONG_LONG_MAX % (__u64)base);
618         for (acc = 0, any = 0;; c = *s++) {
619                 if (cfs_isdigit(c))
620                         c -= '0';
621                 else if (cfs_isalpha(c))
622                         c -= cfs_isupper(c) ? 'A' - 10 : 'a' - 10;
623                 else
624                         break;
625                 if (c >= base)
626                         break;
627                if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
628                         any = -1;
629                 else {
630                         any = 1;
631                         acc *= base;
632                         acc += c;
633                 }
634         }
635         if (any < 0) {
636                 acc = ULONG_LONG_MAX;
637         } else if (neg)
638                 acc = 0 - acc;
639         if (endptr != 0)
640                 *endptr = (char *) (any ? s - 1 : nptr);
641         return (acc);
642 }
643
644 #if __KERNEL__
645
646 #define BASE 65521L /* largest prime smaller than 65536 */
647 #define NMAX 5552
648 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
649
650 #define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
651 #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
652 #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
653 #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
654 #define DO16(buf)   DO8(buf,0); DO8(buf,8);
655
656 /* ========================================================================= */
657 /* 
658     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
659   return the updated checksum. If buf is NULL, this function returns
660   the required initial value for the checksum.
661   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
662   much faster. Usage example:
663
664     uLong adler = adler32(0L, NULL, 0);
665
666     while (read_buffer(buffer, length) != EOF) {
667       adler = adler32(adler, buffer, length);
668     }
669     if (adler != original_adler) error();
670 */
671
672 ULONG zlib_adler32(ULONG adler,
673                    const BYTE *buf,
674                    UINT len)
675 {
676     unsigned long s1 = adler & 0xffff;
677     unsigned long s2 = (adler >> 16) & 0xffff;
678     int k;
679
680     if (buf == NULL) return 1L;
681
682     while (len > 0) {
683         k = len < NMAX ? len : NMAX;
684         len -= k;
685         while (k >= 16) {
686             DO16(buf);
687             buf += 16;
688             k -= 16;
689         }
690         if (k != 0) do {
691             s1 += *buf++;
692             s2 += s1;
693         } while (--k);
694         s1 %= BASE;
695         s2 %= BASE;
696     }
697     return (s2 << 16) | s1;
698 }
699
700 #if  !defined(NTDDI_VERSION) || NTDDI_VERSION < 0x06000000
701 _CRTIMP size_t  __cdecl strnlen(const char * _Str, size_t _MaxCount)
702 {
703         size_t len = 0;
704         while(len < _MaxCount && _Str[len++]);
705         return len;
706 }
707 #endif
708
709 int (__cdecl *_cfs_isalpha)(int);
710 int (__cdecl *_cfs_isspace)(int);
711 int (__cdecl *_cfs_isupper)(int);
712 int (__cdecl *_cfs_isdigit)(int);
713 int (__cdecl *_cfs_isxdigit)(int);
714
715 int cfs_isalpha(int c)
716 {
717     if (_cfs_isalpha) {
718         return _cfs_isalpha(c);
719     } else {
720         return ((c >= 'a' && c <= 'z') ||
721                 (c >= 'A' && c <= 'Z'));
722     }
723 }
724
725 int cfs_isspace(int c)
726 {
727     if (_cfs_isspace) {
728         return _cfs_isspace(c);
729     } else {
730         return ((c >= 0x09 && c <= 0x0d) ||
731                 (c == 0x20));
732     }
733 }
734
735 int cfs_isupper(int c)
736 {
737     if (_cfs_isupper) {
738         return _cfs_isupper(c);
739     } else {
740         return (c >= 'A' && c <= 'Z');
741     }
742 }
743
744 int cfs_isdigit(int c)
745 {
746     if (_cfs_isdigit) {
747         return _cfs_isdigit(c);
748     } else {
749         return (c >= '0' && c <= '9');
750     }
751 }
752
753 int cfs_isxdigit(int c)
754 {
755     if (_cfs_isxdigit) {
756         return _cfs_isxdigit(c);
757     } else {
758         return ((c >= '0' && c <= '9') ||
759                 (c >= 'A' && c <= 'F') ||
760                 (c >= 'a' && c <= 'F'));
761     }
762 }
763
764 void cfs_libc_init()
765 {
766     UNICODE_STRING  fn;
767     int             i;
768
769     struct {WCHAR * name; PVOID * addr;} funcs[] = {
770             { L"isspace", (PVOID *)&_cfs_isspace},
771             { L"isalpha", (PVOID *)&_cfs_isalpha},
772             { L"isupper", (PVOID *)&_cfs_isupper},
773             { L"isdigit", (PVOID *)&_cfs_isdigit},
774             { L"isxdigit",(PVOID *)&_cfs_isxdigit},
775             { NULL, NULL },
776             };
777
778     for (i=0; funcs[i].name != NULL; i++) {
779         RtlInitUnicodeString(&fn, funcs[i].name);
780         *(funcs[i].addr) = MmGetSystemRoutineAddress(&fn);
781     }
782
783 #if DBG
784     ASSERT(cfs_isspace(0x20) && cfs_isspace(0x09) &&
785            cfs_isspace(0x0a) && cfs_isspace(0x0d) &&
786            !cfs_isspace('a') && !cfs_isspace('0'));
787     ASSERT(cfs_isalpha('a')  && cfs_isalpha('Z') && 
788            !cfs_isalpha('0') && !cfs_isalpha('='));
789     ASSERT(cfs_isupper('A')  && cfs_isupper('Z') && 
790            !cfs_isupper('a') && !cfs_isupper('='));
791     ASSERT(cfs_isdigit('0')   && cfs_isdigit('9') && 
792            !cfs_isdigit('a')  && !cfs_isdigit('#'));
793     ASSERT(cfs_isxdigit('0')  && cfs_isxdigit('9') && 
794            cfs_isxdigit('a')  && cfs_isxdigit('A') &&
795            cfs_isxdigit('F')  && cfs_isxdigit('f') &&
796            !cfs_isxdigit('G') && !cfs_isxdigit('z'));
797 #endif    
798 }
799
800 #else
801
802 unsigned int libcfs_subsystem_debug = ~0;
803
804 int cfs_isalpha(int c)
805 {
806     return isalpha(c);
807 }
808
809 int cfs_isspace(int c)
810 {
811     return isspace(c);
812 }
813
814 int cfs_isupper(int c)
815 {
816     return isupper(c);
817 }
818
819 int cfs_isdigit(int c)
820 {
821     return isdigit(c);
822 }
823
824 int cfs_isxdigit(int c)
825 {
826     return isxdigit(c);
827 }
828
829 void cfs_libc_init()
830 {
831 }
832
833
834 #endif