os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixCompat.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2  * tclUnixCompat.c
     3  *
     4  * Written by: Zoran Vasiljevic (vasiljevic@users.sourceforge.net).
     5  *
     6  * See the file "license.terms" for information on usage and redistribution
     7  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
     8  *
     9  * RCS: @(#) $Id: tclUnixCompat.c,v 1.1.2.10 2006/09/12 22:05:03 andreas_kupries Exp $
    10  *
    11  */
    12 
    13 #include "tclInt.h"
    14 #include "tclPort.h"
    15 #include <pwd.h>
    16 #include <grp.h>
    17 #include <errno.h>
    18 #include <string.h>
    19 
    20 /*
    21  * Used to pad structures at size'd boundaries
    22  *
    23  * This macro assumes that the pointer 'buffer' was created from an
    24  * aligned pointer by adding the 'length'. If this 'length' was not a
    25  * multiple of the 'size' the result is unaligned and PadBuffer
    26  * corrects both the pointer, _and_ the 'length'. The latter means
    27  * that future increments of 'buffer' by 'length' stay aligned.
    28  */
    29 
    30 #define PadBuffer(buffer, length, size)             \
    31     if (((length) % (size))) {                      \
    32 	(buffer) += ((size) - ((length) % (size))); \
    33 	(length) += ((size) - ((length) % (size))); \
    34     }
    35 
    36 /*
    37  * Per-thread private storage used to store values
    38  * returned from MT-unsafe library calls.
    39  */
    40 
    41 #ifdef TCL_THREADS
    42 
    43 typedef struct ThreadSpecificData {
    44 
    45     struct passwd pwd;
    46     char pbuf[2048];
    47 
    48     struct group grp;
    49     char gbuf[2048];
    50 
    51 #if !defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)
    52     struct hostent hent;
    53     char hbuf[2048];
    54 #endif
    55 
    56 }  ThreadSpecificData;
    57 
    58 static Tcl_ThreadDataKey dataKey;
    59 
    60 #if ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \
    61      (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \
    62       !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \
    63       !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R)
    64 
    65 /*
    66  * Mutex to lock access to MT-unsafe calls. This is just to protect
    67  * our own usage. It does not protect us from others calling the
    68  * same functions without (or using some different) lock.
    69  */
    70 
    71 static Tcl_Mutex compatLock;
    72 
    73 /*
    74  *---------------------------------------------------------------------------
    75  *
    76  * CopyArray --
    77  *
    78  *      Copies array of NULL-terminated or fixed-length strings
    79  *      to the private buffer, honouring the size of the buffer.
    80  *
    81  * Results:
    82  *      Number of bytes copied on success or -1 on error (errno = ERANGE)
    83  *
    84  * Side effects:
    85  *      None.
    86  *
    87  *---------------------------------------------------------------------------
    88  */
    89 
    90 static int
    91 CopyArray(char **src, int elsize, char *buf, int buflen)
    92 {
    93     int i, j, len = 0;
    94     char *p, **new;
    95 
    96     if (src == NULL) {
    97 	return 0;
    98     }
    99     for (i = 0; src[i] != NULL; i++) {
   100 	/* Empty loop to count howmany */
   101     }
   102     if ((sizeof(char *)*(i + 1)) >  buflen) {
   103 	return -1;
   104     }
   105     len = (sizeof(char *)*(i + 1)); /* Leave place for the array */
   106     new = (char **)buf;
   107     p = buf + (sizeof(char *)*(i + 1));
   108     for (j = 0; j < i; j++) {
   109 	if (elsize < 0) {
   110 	    len += strlen(src[j]) + 1;
   111 	} else {
   112 	    len += elsize;
   113 	}
   114 	if (len > buflen) {
   115 	    return -1;
   116 	}
   117 	if (elsize < 0) {
   118 	    strcpy(p, src[j]);
   119 	} else {
   120 	    memcpy(p, src[j], elsize);
   121 	}
   122 	new[j] = p;
   123 	p = buf + len;
   124     }
   125     new[j] = NULL;
   126 
   127     return len;
   128 }
   129 
   130 
   131 /*
   132  *---------------------------------------------------------------------------
   133  *
   134  * CopyString --
   135  *
   136  *      Copies a NULL-terminated string to the private buffer,
   137  *      honouring the size of the buffer
   138  *
   139  * Results:
   140  *      0 success or -1 on error (errno = ERANGE)
   141  *
   142  * Side effects:
   143  *      None
   144  *
   145  *---------------------------------------------------------------------------
   146  */
   147 
   148 
   149 static int
   150 CopyString(char *src, char *buf, int buflen)
   151 {
   152     int len = 0;
   153 
   154     if (src != NULL) {
   155 	len += strlen(src) + 1;
   156 	if (len > buflen) {
   157 	    return -1;
   158 	}
   159 	strcpy(buf, src);
   160     }
   161 
   162     return len;
   163 }
   164 #endif /* ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \
   165 	   (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \
   166 	    !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \
   167 	    !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */
   168 
   169 #if (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \
   170     (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))
   171 
   172 /*
   173  *---------------------------------------------------------------------------
   174  *
   175  * CopyHostnent --
   176  *
   177  *      Copies string fields of the hostnent structure to the
   178  *      private buffer, honouring the size of the buffer.
   179  *
   180  * Results:
   181  *      Number of bytes copied on success or -1 on error (errno = ERANGE)
   182  *
   183  * Side effects:
   184  *      None
   185  *
   186  *---------------------------------------------------------------------------
   187  */
   188 
   189 static int
   190 CopyHostent(struct hostent *tgtPtr, char *buf, int buflen)
   191 {
   192     char *p = buf;
   193     int copied, len = 0;
   194 
   195     copied = CopyString(tgtPtr->h_name, p, buflen - len);
   196     if (copied == -1) {
   197     range:
   198 	errno = ERANGE;
   199 	return -1;
   200     }
   201     tgtPtr->h_name = (copied > 0) ? p : NULL;
   202     len += copied;
   203     p = buf + len;
   204 
   205     PadBuffer(p, len, sizeof(char *));
   206     copied = CopyArray(tgtPtr->h_aliases, -1, p, buflen - len);
   207     if (copied == -1) {
   208 	goto range;
   209     }
   210     tgtPtr->h_aliases = (copied > 0) ? (char **)p : NULL;
   211     len += copied;
   212     p += len;
   213 
   214     PadBuffer(p, len, sizeof(char *));
   215     copied = CopyArray(tgtPtr->h_addr_list, tgtPtr->h_length, p, buflen - len);
   216     if (copied == -1) {
   217 	goto range;
   218     }
   219     tgtPtr->h_addr_list = (copied > 0) ? (char **)p : NULL;
   220 
   221     return 0;
   222 }
   223 #endif /* (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \
   224 	  (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)) */
   225 
   226 #if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R)
   227 
   228 /*
   229  *---------------------------------------------------------------------------
   230  *
   231  * CopyPwd --
   232  *
   233  *      Copies string fields of the passwd structure to the
   234  *      private buffer, honouring the size of the buffer.
   235  *
   236  * Results:
   237  *      0 on success or -1 on error (errno = ERANGE)
   238  *
   239  * Side effects:
   240  *      We are not copying the gecos field as it may not be supported
   241  *      on all platforms.
   242  *
   243  *---------------------------------------------------------------------------
   244  */
   245 
   246 static int
   247 CopyPwd(struct passwd *tgtPtr, char *buf, int buflen)
   248 {
   249     char *p = buf;
   250     int copied, len = 0;
   251 
   252     copied = CopyString(tgtPtr->pw_name, p, buflen - len);
   253     if (copied == -1) {
   254     range:
   255 	errno = ERANGE;
   256 	return -1;
   257     }
   258     tgtPtr->pw_name = (copied > 0) ? p : NULL;
   259     len += copied;
   260     p = buf + len;
   261 
   262     copied = CopyString(tgtPtr->pw_passwd, p, buflen - len);
   263     if (copied == -1) {
   264 	goto range;
   265     }
   266     tgtPtr->pw_passwd = (copied > 0) ? p : NULL;
   267     len += copied;
   268     p = buf + len;
   269 
   270     copied = CopyString(tgtPtr->pw_dir, p, buflen - len);
   271     if (copied == -1) {
   272 	goto range;
   273     }
   274     tgtPtr->pw_dir = (copied > 0) ? p : NULL;
   275     len += copied;
   276     p = buf + len;
   277 
   278     copied = CopyString(tgtPtr->pw_shell, p, buflen - len);
   279     if (copied == -1) {
   280 	goto range;
   281     }
   282     tgtPtr->pw_shell = (copied > 0) ? p : NULL;
   283 
   284     return 0;
   285 }
   286 #endif /* !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) */
   287 
   288 #if !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R)
   289 
   290 /*
   291  *---------------------------------------------------------------------------
   292  *
   293  * CopyGrp --
   294  *
   295  *      Copies string fields of the group structure to the
   296  *      private buffer, honouring the size of the buffer.
   297  *
   298  * Results:
   299  *      0 on success or -1 on error (errno = ERANGE)
   300  *
   301  * Side effects:
   302  *      None.
   303  *
   304  *---------------------------------------------------------------------------
   305  */
   306 
   307 static int
   308 CopyGrp(struct group *tgtPtr, char *buf, int buflen)
   309 {
   310     register char *p = buf;
   311     register int copied, len = 0;
   312 
   313     /* Copy username */
   314     copied = CopyString(tgtPtr->gr_name, p, buflen - len);
   315     if (copied == -1) {
   316     range:
   317 	errno = ERANGE;
   318 	return -1;
   319     }
   320     tgtPtr->gr_name = (copied > 0) ? p : NULL;
   321     len += copied;
   322     p = buf + len;
   323 
   324     /* Copy password */
   325     copied = CopyString(tgtPtr->gr_passwd, p, buflen - len);
   326     if (copied == -1) {
   327 	goto range;
   328     }
   329     tgtPtr->gr_passwd = (copied > 0) ? p : NULL;
   330     len += copied;
   331     p = buf + len;
   332 
   333     /* Copy group members */
   334     PadBuffer(p, len, sizeof(char *));
   335     copied = CopyArray((char **)tgtPtr->gr_mem, -1, p, buflen - len);
   336     if (copied == -1) {
   337 	goto range;
   338     }
   339     tgtPtr->gr_mem = (copied > 0) ? (char **)p : NULL;
   340 
   341     return 0;
   342 }
   343 #endif /* !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */
   344 
   345 #endif /* TCL_THREADS */
   346 
   347 
   348 /*
   349  *---------------------------------------------------------------------------
   350  *
   351  * TclpGetPwNam --
   352  *
   353  *      Thread-safe wrappers for getpwnam().
   354  *      See "man getpwnam" for more details.
   355  *
   356  * Results:
   357  *      Pointer to struct passwd on success or NULL on error.
   358  *
   359  * Side effects:
   360  *      None.
   361  *
   362  *---------------------------------------------------------------------------
   363  */
   364 
   365 struct passwd *
   366 TclpGetPwNam(const char *name)
   367 {
   368 #if !defined(TCL_THREADS)
   369     return getpwnam(name);
   370 #else
   371     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   372 
   373 #if defined(HAVE_GETPWNAM_R_5)
   374     struct passwd *pwPtr = NULL;
   375     return (getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf),
   376 		       &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL;
   377 
   378 #elif defined(HAVE_GETPWNAM_R_4)
   379     return getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf));
   380 
   381 #else
   382     struct passwd *pwPtr;
   383     Tcl_MutexLock(&compatLock);
   384     pwPtr = getpwnam(name);
   385     if (pwPtr != NULL) {
   386 	tsdPtr->pwd = *pwPtr;
   387 	pwPtr = &tsdPtr->pwd;
   388 	if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) {
   389 	    pwPtr = NULL;
   390 	}
   391     }
   392     Tcl_MutexUnlock(&compatLock);
   393     return pwPtr;
   394 #endif
   395     return NULL; /* Not reached */
   396 #endif /* TCL_THREADS */
   397 }
   398 
   399 
   400 /*
   401  *---------------------------------------------------------------------------
   402  *
   403  * TclpGetPwUid --
   404  *
   405  *      Thread-safe wrappers for getpwuid().
   406  *      See "man getpwuid" for more details.
   407  *
   408  * Results:
   409  *      Pointer to struct passwd on success or NULL on error.
   410  *
   411  * Side effects:
   412  *      None.
   413  *
   414  *---------------------------------------------------------------------------
   415  */
   416 
   417 struct passwd *
   418 TclpGetPwUid(uid_t uid)
   419 {
   420 #if !defined(TCL_THREADS)
   421     return getpwuid(uid);
   422 #else
   423     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   424 
   425 #if defined(HAVE_GETPWUID_R_5)
   426     struct passwd *pwPtr = NULL;
   427     return (getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf),
   428 		       &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL;
   429 
   430 #elif defined(HAVE_GETPWUID_R_4)
   431     return getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf));
   432 
   433 #else
   434     struct passwd *pwPtr;
   435     Tcl_MutexLock(&compatLock);
   436     pwPtr = getpwuid(uid);
   437     if (pwPtr != NULL) {
   438 	tsdPtr->pwd = *pwPtr;
   439 	pwPtr = &tsdPtr->pwd;
   440 	if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) {
   441 	    pwPtr = NULL;
   442 	}
   443     }
   444     Tcl_MutexUnlock(&compatLock);
   445     return pwPtr;
   446 #endif
   447     return NULL; /* Not reached */
   448 #endif /* TCL_THREADS */
   449 }
   450 
   451 
   452 /*
   453  *---------------------------------------------------------------------------
   454  *
   455  * TclpGetGrNam --
   456  *
   457  *      Thread-safe wrappers for getgrnam().
   458  *      See "man getgrnam" for more details.
   459  *
   460  * Results:
   461  *      Pointer to struct group on success or NULL on error.
   462  *
   463  * Side effects:
   464  *      None.
   465  *
   466  *---------------------------------------------------------------------------
   467  */
   468 
   469 struct group *
   470 TclpGetGrNam(const char *name)
   471 {
   472 #if !defined(TCL_THREADS)
   473     return getgrnam(name);
   474 #else
   475     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   476 
   477 #if defined(HAVE_GETGRNAM_R_5)
   478     struct group *grPtr = NULL;
   479     return (getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf),
   480 		       &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL;
   481 
   482 #elif defined(HAVE_GETGRNAM_R_4)
   483     return getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf));
   484 
   485 #else
   486     struct group *grPtr;
   487     Tcl_MutexLock(&compatLock);
   488     grPtr = getgrnam(name);
   489     if (grPtr != NULL) {
   490 	tsdPtr->grp = *grPtr;
   491 	grPtr = &tsdPtr->grp;
   492 	if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) {
   493 	    grPtr = NULL;
   494 	}
   495     }
   496     Tcl_MutexUnlock(&compatLock);
   497     return grPtr;
   498 #endif
   499     return NULL; /* Not reached */
   500 #endif /* TCL_THREADS */
   501 }
   502 
   503 
   504 /*
   505  *---------------------------------------------------------------------------
   506  *
   507  * TclpGetGrGid --
   508  *
   509  *      Thread-safe wrappers for getgrgid().
   510  *      See "man getgrgid" for more details.
   511  *
   512  * Results:
   513  *      Pointer to struct group on success or NULL on error.
   514  *
   515  * Side effects:
   516  *      None.
   517  *
   518  *---------------------------------------------------------------------------
   519  */
   520 
   521 struct group *
   522 TclpGetGrGid(gid_t gid)
   523 {
   524 #if !defined(TCL_THREADS)
   525     return getgrgid(gid);
   526 #else
   527     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   528 
   529 #if defined(HAVE_GETGRGID_R_5)
   530     struct group *grPtr = NULL;
   531     return (getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf),
   532 		       &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL;
   533 
   534 #elif defined(HAVE_GETGRGID_R_4)
   535     return getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf));
   536 
   537 #else
   538     struct group *grPtr;
   539     Tcl_MutexLock(&compatLock);
   540     grPtr = getgrgid(gid);
   541     if (grPtr != NULL) {
   542 	tsdPtr->grp = *grPtr;
   543 	grPtr = &tsdPtr->grp;
   544 	if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) {
   545 	    grPtr = NULL;
   546 	}
   547     }
   548     Tcl_MutexUnlock(&compatLock);
   549     return grPtr;
   550 #endif
   551     return NULL; /* Not reached */
   552 #endif /* TCL_THREADS */
   553 }
   554 
   555 
   556 /*
   557  *---------------------------------------------------------------------------
   558  *
   559  * TclpGetHostByName --
   560  *
   561  *      Thread-safe wrappers for gethostbyname().
   562  *      See "man gethostbyname" for more details.
   563  *
   564  * Results:
   565  *      Pointer to struct hostent on success or NULL on error.
   566  *
   567  * Side effects:
   568  *      None.
   569  *
   570  *---------------------------------------------------------------------------
   571  */
   572 
   573 struct hostent *
   574 TclpGetHostByName(const char *name)
   575 {
   576 #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYNAME)
   577     return gethostbyname(name);
   578 #else
   579     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   580 
   581 #if defined(HAVE_GETHOSTBYNAME_R_5)
   582     int h_errno;
   583     return gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf,
   584 			   sizeof(tsdPtr->hbuf), &h_errno);
   585 
   586 #elif defined(HAVE_GETHOSTBYNAME_R_6)
   587     struct hostent *hePtr;
   588     int h_errno;
   589     return (gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf,
   590 			    sizeof(tsdPtr->hbuf), &hePtr, &h_errno) == 0) ?
   591 	&tsdPtr->hent : NULL;
   592 
   593 #elif defined(HAVE_GETHOSTBYNAME_R_3)
   594     struct hostent_data data;
   595     return (gethostbyname_r(name, &tsdPtr->hent, &data) == 0) ?
   596 	&tsdPtr->hent : NULL;
   597 #else
   598     struct hostent *hePtr;
   599     Tcl_MutexLock(&compatLock);
   600     hePtr = gethostbyname(name);
   601     if (hePtr != NULL) {
   602 	tsdPtr->hent = *hePtr;
   603 	hePtr = &tsdPtr->hent;
   604 	if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf,
   605 			sizeof(tsdPtr->hbuf)) == -1) {
   606 	    hePtr = NULL;
   607 	}
   608     }
   609     Tcl_MutexUnlock(&compatLock);
   610     return hePtr;
   611 #endif
   612     return NULL; /* Not reached */
   613 #endif /* TCL_THREADS */
   614 }
   615 
   616 
   617 /*
   618  *---------------------------------------------------------------------------
   619  *
   620  * TclpGetHostByAddr --
   621  *
   622  *      Thread-safe wrappers for gethostbyaddr().
   623  *      See "man gethostbyaddr" for more details.
   624  *
   625  * Results:
   626  *      Pointer to struct hostent on success or NULL on error.
   627  *
   628  * Side effects:
   629  *      None.
   630  *
   631  *---------------------------------------------------------------------------
   632  */
   633 
   634 struct hostent *
   635 TclpGetHostByAddr(const char *addr, int length, int type)
   636 {
   637 #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYADDR)
   638     return gethostbyaddr(addr, length, type);
   639 #else
   640     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   641 
   642 #if defined(HAVE_GETHOSTBYADDR_R_7)
   643     int h_errno;
   644     return gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf,
   645 			   sizeof(tsdPtr->hbuf), &h_errno);
   646 
   647 #elif defined(HAVE_GETHOSTBYADDR_R_8)
   648     struct hostent *hePtr;
   649     int h_errno;
   650     return (gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf,
   651 			    sizeof(tsdPtr->hbuf), &hePtr, &h_errno) == 0) ?
   652 	&tsdPtr->hent : NULL;
   653 #else
   654     struct hostent *hePtr;
   655     Tcl_MutexLock(&compatLock);
   656     hePtr = gethostbyaddr(addr, length, type);
   657     if (hePtr != NULL) {
   658 	tsdPtr->hent = *hePtr;
   659 	hePtr = &tsdPtr->hent;
   660 	if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf,
   661 			sizeof(tsdPtr->hbuf)) == -1) {
   662 	    hePtr = NULL;
   663 	}
   664     }
   665     Tcl_MutexUnlock(&compatLock);
   666     return hePtr;
   667 #endif
   668     return NULL; /* Not reached */
   669 #endif /* TCL_THREADS */
   670 }