diff options
Diffstat (limited to 'ldap/servers/slapd/fileio.c')
-rw-r--r-- | ldap/servers/slapd/fileio.c | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/ldap/servers/slapd/fileio.c b/ldap/servers/slapd/fileio.c new file mode 100644 index 00000000..f3e90b10 --- /dev/null +++ b/ldap/servers/slapd/fileio.c @@ -0,0 +1,336 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* fileio.c - layer to adjust EOL to use DOS format via PR_Read/Write on NT */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> +#ifndef _WIN32 +#include <sys/param.h> +#include <unistd.h> +#include <pwd.h> +#endif +#include "slap.h" +#include "pw.h" +#include <prio.h> + +#if defined( XP_WIN32 ) + +#include <prinit.h> /* PR_CallOnce */ +#include <string.h> /* memmove, memcpy */ + +#define g_EOF (-1) + +static PRInt32 PR_CALLBACK readText(PRFileDesc *f, void *buf, PRInt32 amount) +{ + auto PRInt32 size = *(signed char*)&(f->secret); + auto char* readAhead = ((char*)&(f->secret)) + 1; + if ( size == g_EOF ) { + f->secret = NULL; + return 0; + } + if ( size > amount ) { + return 0; + } + if ( size > 0 ) { + memcpy( buf, readAhead, size ); + } + f->secret = NULL; + while (1) { + auto PRInt32 len = amount - size; + auto char* head; + auto PRInt32 rval; + if (len > 0) { + head = (char*)buf + size; + } else if (size > 0 && '\r' == ((char*)buf)[size-1]) { + head = readAhead; + len = 1; + } else { + break; + } + rval = PR_Read( f->lower, head, len ); + if ( rval < 0 ) { /* error */ + return rval; + } + if ( rval == 0 ) { /* EOF */ + if ( size ) { + *(signed char*)&(f->secret) = g_EOF; + } + return size; + } + if (head == readAhead) { + if ( '\n' == *readAhead ) { + ((char*)buf)[size-1] = '\n'; + } else { + *(signed char*)&(f->secret) = rval; + } + break; + } else { + auto char* tail = head + rval; + auto char* dest = NULL; + auto char* p; + for ( p = head; p < tail; p++ ) { + if ( *p == '\n' && p > (char*)buf && *(p - 1) == '\r' ) + { + if ( dest == NULL ) { /* first CRLF */ + dest = p - 1; + } else { + auto size_t len = (p - 1) - head; + memmove( dest, head, len ); + dest += len; + } + head = p; /* '\n' */ + --rval; /* ignore '\r' */ + } + } + if ( dest != NULL ) { + auto size_t len = tail - head; + memmove( dest, head, len ); + } + size += rval; + } + } + return size; +} + +static PRInt32 PR_CALLBACK seekText(PRFileDesc *f, PRInt32 offset, PRSeekWhence how) +{ + f->secret = NULL; + return PR_Seek(f->lower, offset, how); +} + +static PRInt64 PR_CALLBACK seek64Text(PRFileDesc *f, PRInt64 offset, PRSeekWhence how) +{ + f->secret = NULL; + return PR_Seek64(f->lower, offset, how); +} + +static PRInt32 PR_CALLBACK writeText(PRFileDesc *f, const void *buf, PRInt32 amount) +{ + /* note: buf might not be null-terminated */ + auto PRInt32 size = 0; + auto char* head = (char*)buf; + auto char* tail = head + amount; + auto char* p; + for ( p = head; p <= tail; ++p ) { + if ( p == tail || *p == '\n' ) { + auto PRInt32 len = p - head; + auto PRInt32 rval; + if ( len > 0 ) { + rval = PR_Write( f->lower, head, len ); + if ( rval < 0 ) { + return rval; + } + size += rval; + if ( rval < len ) { + break; + } + } + if ( p == tail ) { + break; + } + rval = PR_Write( f->lower, "\r", 1 ); + if ( rval < 0 ) { + return rval; + } + if ( rval < 1 ) { + break; + } + head = p; + } + } + return size; +} + +static PRInt32 PR_CALLBACK writevText(PRFileDesc *fd, const PRIOVec *iov, PRInt32 size, PRIntervalTime timeout) +{ + auto PRInt32 i; + auto size_t total = 0; + for (i = 0; i < size; ++i) { + register PRInt32 rval = PR_Write(fd, iov[i].iov_base, iov[i].iov_len); + if (rval < 0) return rval; + total += rval; + if (rval < iov[i].iov_len) break; + } + return total; +} + +/* ONREPL - this is bad because it allows only one thread to use this functionality. + Noriko said she would fix this before 5.0 ships. + */ + +static const char* const g_LayerName = "MdsTextIO"; +static PRDescIdentity g_LayerID; +static PRIOMethods g_IoMethods; + +static PRStatus PR_CALLBACK closeLayer(PRFileDesc* stack) +{ + auto PRFileDesc* layer = PR_PopIOLayer(stack, g_LayerID); + if (!layer) + return PR_FAILURE; + if (layer->dtor) { + layer->secret = NULL; + layer->dtor(layer); + } + return PR_Close(stack); +} + +static PRStatus PR_CALLBACK initialize(void) +{ + g_LayerID = PR_GetUniqueIdentity(g_LayerName); + if (PR_INVALID_IO_LAYER == g_LayerID) { + return PR_FAILURE; + } else { + auto const PRIOMethods* defaults = PR_GetDefaultIOMethods(); + if (!defaults) { + return PR_FAILURE; + } else { + memcpy (&g_IoMethods, defaults, sizeof(g_IoMethods)); + } + } + /* Customize methods: */ + g_IoMethods.read = readText; + g_IoMethods.seek = seekText; + g_IoMethods.seek64 = seek64Text; + g_IoMethods.write = writeText; + g_IoMethods.writev = writevText; /* ??? Is this necessary? */ + g_IoMethods.close = closeLayer; /* ??? Is this necessary? */ + return PR_SUCCESS; +} + +static PRCallOnceType g_callOnce = {0,0}; + +/* Push a layer that converts from "\n" to the local filesystem's + * end-of-line sequence on output, and vice-versa on input. + * The layer pops itself (if necessary) when the file is closed. + * + * This layer does not affect the behavior of PR_Seek or PR_Seek64; + * their parameters still measure bytes in the lower-level file, + * and consequently will not add up with the results of PR_Read + * or PR_Write. For example, if you add up PR_Read return values, + * and seek backward in the file that many bytes, the cursor will + * *not* be restored to its original position (unless the data you + * read didn't require conversion; that is, they didn't contain + * any newlines, or you're running on Unix). + * + * Likewise, the results of PR_Read or PR_Write won't add up to + * the 'size' field in the result of PRFileInfo or PRFileInfo64. + */ +static PRStatus pushTextIOLayer(PRFileDesc* stack) +{ + auto PRStatus rv = PR_CallOnce(&g_callOnce, initialize); + if (PR_SUCCESS == rv) { + auto PRFileDesc* layer = PR_CreateIOLayerStub(g_LayerID, &g_IoMethods); + layer->secret = NULL; + rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, layer); + } + return rv; +} + +static PRFileDesc *popTextIOLayer(PRFileDesc* stack) +{ + PRFileDesc *layer; + layer = PR_PopIOLayer(stack, g_LayerID); + if (layer && layer->dtor) { + layer->secret = NULL; + layer->dtor(layer); + } + return layer; +} + +#endif /* XP_WIN32 */ + +PRInt32 +slapi_read_buffer( PRFileDesc *fd, void *buf, PRInt32 amount ) +{ + PRInt32 rval = 0; +#if defined( XP_WIN32 ) + PRStatus rv; + + rv = pushTextIOLayer( fd ); + if ( PR_SUCCESS != rv ) { + return -1; + } +#endif + + rval = PR_Read( fd, buf, amount ); + +#if defined( XP_WIN32 ) + popTextIOLayer( fd ); +#endif + + return rval; +} + +/* + * slapi_write_buffer -- same as PR_Write + * except '\r' is added before '\n'. + * Return value: written bytes not including '\r' characters. + */ +PRInt32 +slapi_write_buffer( PRFileDesc *fd, void *buf, PRInt32 amount ) +{ + PRInt32 rval = 0; +#if defined( XP_WIN32 ) + PRStatus rv; + + rv = pushTextIOLayer( fd ); + if ( PR_SUCCESS != rv ) { + return -1; + } +#endif + + rval = PR_Write( fd, buf, amount ); + +#if defined( XP_WIN32 ) + popTextIOLayer( fd ); +#endif + + return rval; +} + +/* + * This function renames a file to a new name. Unlike PR_Rename or NT rename, this + * function can be used if the destfilename exists, and it will overwrite the dest + * file name + */ +int +slapi_destructive_rename(const char *srcfilename, const char *destfilename) +{ + int rv = 0; +#if defined( XP_WIN32 ) + if (!MoveFileEx(srcfilename, destfilename, MOVEFILE_REPLACE_EXISTING)) { + rv = GetLastError(); + } +#else + if ( rename(srcfilename, destfilename) < 0 ) { + rv = errno; + } +#endif + return rv; +} + +/* + * This function copies the source into the dest + */ +int +slapi_copy(const char *srcfilename, const char *destfilename) +{ + int rv = 0; +#if defined( XP_WIN32 ) + if (!CopyFile(srcfilename, destfilename, FALSE)) { + rv = GetLastError(); + } +#else + unlink(destfilename); + if ( link(srcfilename, destfilename) < 0 ) { + rv = errno; + } +#endif + return rv; +} |