gecko-dev/security/nss/lib/base/error.c

299 lines
6.8 KiB
C

/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#ifdef DEBUG
static const char CVS_ID[] = "@(#) $RCSfile: error.c,v $ $Revision: 1.2 $ $Date: 2000/05/17 20:19:23 $ $Name: $";
#endif /* DEBUG */
/*
* error.c
*
* This file contains the code implementing the per-thread error
* stacks upon which most NSS routines report their errors.
*/
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
/*
* The stack itself has a header, and a sequence of integers.
* The header records the amount of space (as measured in stack
* slots) already allocated for the stack, and the count of the
* number of records currently being used.
*/
struct stack_header_str {
PRUint16 space;
PRUint16 count;
};
struct error_stack_str {
struct stack_header_str header;
PRInt32 stack[1];
};
typedef struct error_stack_str error_stack;
/*
* error_stack_index
*
* Thread-private data must be indexed. This is that index.
* See PR_NewThreadPrivateIndex for more information.
*/
static PRUintn error_stack_index;
/*
* call_once
*
* The thread-private index must be obtained (once!) at runtime.
* This block is used for that one-time call.
*/
static PRCallOnceType error_call_once;
/*
* error_once_function
*
* This is the once-called callback.
*/
static PRStatus
error_once_function
(
void
)
{
return nss_NewThreadPrivateIndex(&error_stack_index);
/* return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free); */
}
/*
* error_get_my_stack
*
* This routine returns the calling thread's error stack, creating
* it if necessary. It may return NULL upon error, which implicitly
* means that it ran out of memory.
*/
static error_stack *
error_get_my_stack
(
void
)
{
PRStatus st;
error_stack *rv;
PRUintn new_size;
PRUint32 new_bytes;
error_stack *new_stack;
if( 0 == error_stack_index ) {
st = PR_CallOnce(&error_call_once, error_once_function);
if( PR_SUCCESS != st ) {
return (error_stack *)NULL;
}
}
rv = (error_stack *)nss_GetThreadPrivate(error_stack_index);
if( (error_stack *)NULL == rv ) {
/* Doesn't exist; create one */
new_size = 16;
} else {
if( rv->header.count == rv->header.space ) {
/* Too small, expand it */
new_size = rv->header.space + 16;
} else {
/* Okay, return it */
return rv;
}
}
new_bytes = (new_size * sizeof(PRInt32)) +
sizeof(struct stack_header_str);
/* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */
if( (error_stack *)NULL == rv ) {
new_stack = PR_Calloc(1, new_bytes);
} else {
new_stack = PR_Realloc(rv, new_bytes);
}
if( (error_stack *)NULL != new_stack ) {
new_stack->header.space = new_size;
}
/* Set the value, whether or not the allocation worked */
nss_SetThreadPrivate(error_stack_index, new_stack);
return new_stack;
}
/*
* The error stack
*
* The public methods relating to the error stack are:
*
* NSS_GetError
* NSS_GetErrorStack
*
* The nonpublic methods relating to the error stack are:
*
* nss_SetError
* nss_ClearErrorStack
*
*/
/*
* NSS_GetError
*
* This routine returns the highest-level (most general) error set
* by the most recent NSS library routine called by the same thread
* calling this routine.
*
* This routine cannot fail. However, it may return zero, which
* indicates that the previous NSS library call did not set an error.
*
* Return value:
* 0 if no error has been set
* A nonzero error number
*/
NSS_IMPLEMENT PRInt32
NSS_GetError
(
void
)
{
error_stack *es = error_get_my_stack();
if( (error_stack *)NULL == es ) {
return NSS_ERROR_NO_MEMORY; /* Good guess! */
}
if( 0 == es->header.count ) {
return 0;
}
return es->stack[ es->header.count-1 ];
}
/*
* NSS_GetErrorStack
*
* This routine returns a pointer to an array of integers, containing
* the entire sequence or "stack" of errors set by the most recent NSS
* library routine called by the same thread calling this routine.
* NOTE: the caller DOES NOT OWN the memory pointed to by the return
* value. The pointer will remain valid until the calling thread
* calls another NSS routine. The lowest-level (most specific) error
* is first in the array, and the highest-level is last. The array is
* zero-terminated. This routine may return NULL upon error; this
* indicates a low-memory situation.
*
* Return value:
* NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
* A NON-caller-owned pointer to an array of integers
*/
NSS_IMPLEMENT PRInt32 *
NSS_GetErrorStack
(
void
)
{
error_stack *es = error_get_my_stack();
if( (error_stack *)NULL == es ) {
return (PRInt32 *)NULL;
}
/* Make sure it's terminated */
es->stack[ es->header.count ] = 0;
return es->stack;
}
/*
* nss_SetError
*
* This routine places a new error code on the top of the calling
* thread's error stack. Calling this routine wiht an error code
* of zero will clear the error stack.
*/
NSS_IMPLEMENT void
nss_SetError
(
PRUint32 error
)
{
error_stack *es;
if( 0 == error ) {
nss_ClearErrorStack();
return;
}
es = error_get_my_stack();
if( (error_stack *)NULL == es ) {
/* Oh, well. */
return;
}
es->stack[ es->header.count ] = error;
es->header.count++;
return;
}
/*
* nss_ClearErrorStack
*
* This routine clears the calling thread's error stack.
*/
NSS_IMPLEMENT void
nss_ClearErrorStack
(
void
)
{
error_stack *es = error_get_my_stack();
if( (error_stack *)NULL == es ) {
/* Oh, well. */
return;
}
es->header.count = 0;
es->stack[0] = 0;
return;
}