summaryrefslogtreecommitdiff
path: root/source3/printing
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2002-09-25 15:19:00 +0000
committerGerald Carter <jerry@samba.org>2002-09-25 15:19:00 +0000
commita834a73e341059be154426390304a42e4a011f72 (patch)
tree7f53b0f7819238e0ee0396daccf5d924cb9b8d29 /source3/printing
parent115a39775cb923d026dde58633b6ba6aef3a1943 (diff)
downloadsamba-a834a73e341059be154426390304a42e4a011f72.tar.gz
samba-a834a73e341059be154426390304a42e4a011f72.tar.bz2
samba-a834a73e341059be154426390304a42e4a011f72.zip
sync'ing up for 3.0alpha20 release
(This used to be commit 65e7b5273bb58802bf0c389b77f7fcae0a1f6139)
Diffstat (limited to 'source3/printing')
-rw-r--r--source3/printing/notify.c120
-rw-r--r--source3/printing/nt_printing.c615
-rw-r--r--source3/printing/print_cups.c8
-rw-r--r--source3/printing/printfsp.c2
-rw-r--r--source3/printing/printing.c427
5 files changed, 864 insertions, 308 deletions
diff --git a/source3/printing/notify.c b/source3/printing/notify.c
index 925d49a21d..003718ed72 100644
--- a/source3/printing/notify.c
+++ b/source3/printing/notify.c
@@ -22,21 +22,99 @@
#include "printing.h"
-/*
- * Print notification routines
- */
+static TALLOC_CTX *send_ctx;
+
+static struct notify_queue {
+ struct notify_queue *next, *prev;
+ void *buf;
+ size_t buflen;
+} *notify_queue_head = NULL;
+
+/*******************************************************************
+ Used to decide if we need a short select timeout.
+*******************************************************************/
+
+BOOL print_notify_messages_pending(void)
+{
+ return (notify_queue_head != NULL);
+}
+
+/*******************************************************************
+ Actually send the batched messages.
+*******************************************************************/
+
+void print_notify_send_messages(void)
+{
+ TDB_CONTEXT *tdb;
+ char *buf;
+ struct notify_queue *pq;
+ size_t msg_count = 0, offset = 0;
+
+ if (!print_notify_messages_pending())
+ return;
+
+ if (!send_ctx)
+ return;
+
+ tdb = conn_tdb_ctx();
+
+ if (!tdb) {
+ DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
+ return;
+ }
+
+ /* Count the space needed to send the messages. */
+ for (pq = notify_queue_head; pq; pq = pq->next, msg_count++)
+ offset += (pq->buflen + 4);
+
+ offset += 4; /* For count. */
+
+ buf = talloc(send_ctx, offset);
+ if (!buf) {
+ DEBUG(0,("print_notify_send_messages: Out of memory\n"));
+ talloc_destroy_pool(send_ctx);
+ return;
+ }
+
+ offset = 0;
+ SIVAL(buf,offset,msg_count);
+ offset += 4;
+ for (pq = notify_queue_head; pq; pq = pq->next) {
+ SIVAL(buf,offset,pq->buflen);
+ offset += 4;
+ memcpy(buf + offset, pq->buf, pq->buflen);
+ offset += pq->buflen;
+ }
+
+ DEBUG(5, ("print_notify_send_messages: sending %d print notify message%s\n",
+ msg_count, msg_count != 1 ? "s" : ""));
+
+ message_send_all(tdb, MSG_PRINTER_NOTIFY2, buf, offset, False, NULL);
+ talloc_destroy_pool(send_ctx);
+ notify_queue_head = NULL;
+}
+
+/*******************************************************************
+ Batch up print notify messages.
+*******************************************************************/
static void send_spoolss_notify2_msg(struct spoolss_notify_msg *msg)
{
char *buf = NULL;
- int buflen = 0, len;
- TDB_CONTEXT *tdb;
+ size_t buflen = 0, len;
+ struct notify_queue *pnqueue, *tmp_ptr;
/* Let's not waste any time with this */
if (lp_disable_spoolss())
return;
+ if (!send_ctx)
+ send_ctx = talloc_init_named("print notify queue");
+
+ if (!send_ctx)
+ goto fail;
+
/* Flatten data into a message */
again:
@@ -59,24 +137,34 @@ again:
msg->len, msg->notify.data);
if (buflen != len) {
- buf = Realloc(buf, len);
+ buf = talloc_realloc(send_ctx, buf, len);
+ if (!buf)
+ goto fail;
buflen = len;
goto again;
}
- /* Send message */
+ /* Store the message on the pending queue. */
- tdb = conn_tdb_ctx();
+ pnqueue = talloc(send_ctx, sizeof(*pnqueue));
+ if (!pnqueue)
+ goto fail;
- if (!tdb) {
- DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
- goto done;
- }
-
- message_send_all(tdb, MSG_PRINTER_NOTIFY2, buf, buflen, False, NULL);
+ pnqueue->buf = buf;
+ pnqueue->buflen = buflen;
+
+ DEBUG(5, ("send_spoolss_notify2_msg: appending message 0x%02x/0x%02x to notify_queue_head\n", msg->type, msg->field));
+
+ /* Note we add to the end of the list to ensure
+ * the messages are sent in the order they were received. JRA.
+ */
+ DLIST_ADD_END(notify_queue_head, pnqueue, tmp_ptr);
+
+ return;
+
+ fail:
-done:
- SAFE_FREE(buf);
+ DEBUG(0,("send_spoolss_notify2_msg: Out of memory.\n"));
}
static void send_notify_field_values(const char *printer_name, uint32 type,
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index 3b85fce020..58eba9d87e 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -1745,7 +1745,7 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
dbuf = tdb_fetch(tdb_drivers, kbuf);
if (!dbuf.dptr)
- return WERR_ACCESS_DENIED;
+ return WERR_UNKNOWN_PRINTER_DRIVER;
len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
&driver.cversion,
@@ -1864,7 +1864,7 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32
NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
int i;
- DEBUG(106,("Dumping printer driver at level [%d]\n", level));
+ DEBUG(20,("Dumping printer driver at level [%d]\n", level));
switch (level)
{
@@ -1905,7 +1905,7 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32
/****************************************************************************
****************************************************************************/
-static int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
+int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
{
int len = 0;
@@ -2282,7 +2282,7 @@ static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
/****************************************************************************
****************************************************************************/
-static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
+int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
{
int len = 0;
int extra_len = 0;
@@ -2407,7 +2407,7 @@ int lookup_printerkey( NT_PRINTER_DATA *data, char *name )
for ( i=0; i<data->num_keys; i++ )
{
- if ( strcmp(data->keys[i].name, name) == 0 ) {
+ if ( strequal(data->keys[i].name, name) ) {
DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
key_index = i;
break;
@@ -2420,32 +2420,169 @@ int lookup_printerkey( NT_PRINTER_DATA *data, char *name )
/****************************************************************************
***************************************************************************/
+
+uint32 get_printer_subkeys( NT_PRINTER_DATA *data, char* key, fstring **subkeys )
+{
+ int i, j;
+ int key_len;
+ int num_subkeys = 0;
+ char *p;
+ fstring *ptr, *subkeys_ptr = NULL;
+ fstring subkeyname;
+
+ if ( !data )
+ return 0;
+
+ for ( i=0; i<data->num_keys; i++ )
+ {
+ if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 )
+ {
+ /* match sure it is a subkey and not the key itself */
+
+ key_len = strlen( key );
+ if ( strlen(data->keys[i].name) == key_len )
+ continue;
+
+ /* get subkey path */
+
+ p = data->keys[i].name + key_len;
+ if ( *p == '\\' )
+ p++;
+ fstrcpy( subkeyname, p );
+ if ( (p = strchr( subkeyname, '\\' )) )
+ *p = '\0';
+
+ /* don't add a key more than once */
+
+ for ( j=0; j<num_subkeys; j++ ) {
+ if ( strequal( subkeys_ptr[j], subkeyname ) )
+ break;
+ }
+
+ if ( j != num_subkeys )
+ continue;
+
+ /* found a match, so allocate space and copy the name */
+
+ if ( !(ptr = Realloc( subkeys_ptr, (num_subkeys+2)*sizeof(fstring))) ) {
+ DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
+ num_subkeys+1));
+ SAFE_FREE( subkeys );
+ return 0;
+ }
+
+ subkeys_ptr = ptr;
+ fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
+ num_subkeys++;
+ }
+
+ }
+
+ /* tag of the end */
+
+ fstrcpy( subkeys_ptr[num_subkeys], "" );
+
+ *subkeys = subkeys_ptr;
+
+ return num_subkeys;
+}
-WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2 )
+/****************************************************************************
+ ***************************************************************************/
+
+WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key )
{
- WERROR result = WERR_OK;
NT_PRINTER_DATA *data;
int i;
+ int removed_keys = 0;
+ int empty_slot;
data = &p2->data;
+ empty_slot = data->num_keys;
+
+ if ( !key )
+ return WERR_INVALID_PARAM;
- for ( i=0; i<data->num_keys; i++ )
+ /* remove all keys */
+
+ if ( !strlen(key) )
{
- DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
- data->keys[i].name));
+ for ( i=0; i<data->num_keys; i++ )
+ {
+ DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
+ data->keys[i].name));
- SAFE_FREE( data->keys[i].name );
- regval_ctr_destroy( &data->keys[i].values );
- }
+ SAFE_FREE( data->keys[i].name );
+ regval_ctr_destroy( &data->keys[i].values );
+ }
- SAFE_FREE( data->keys );
+ DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
+ p2->printername ));
+
+ SAFE_FREE( data->keys );
+ ZERO_STRUCTP( data );
- DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
- p2->printername ));
+ return WERR_OK;
+ }
+
+ /* remove a specific key (and all subkeys) */
- ZERO_STRUCTP( data );
+ for ( i=0; i<data->num_keys; i++ )
+ {
+ if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 )
+ {
+ DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
+ data->keys[i].name));
+
+ SAFE_FREE( data->keys[i].name );
+ regval_ctr_destroy( &data->keys[i].values );
+
+ /* mark the slot as empty */
+
+ ZERO_STRUCTP( &data->keys[i] );
+ }
+ }
+
+ /* find the first empty slot */
+
+ for ( i=0; i<data->num_keys; i++ ) {
+ if ( !data->keys[i].name ) {
+ empty_slot = i;
+ removed_keys++;
+ break;
+ }
+ }
+
+ if ( i == data->num_keys )
+ /* nothing was removed */
+ return WERR_INVALID_PARAM;
+
+ /* move everything down */
- return result;
+ for ( i=empty_slot+1; i<data->num_keys; i++ ) {
+ if ( data->keys[i].name ) {
+ memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
+ ZERO_STRUCTP( &data->keys[i] );
+ empty_slot++;
+ removed_keys++;
+ }
+ }
+
+ /* update count */
+
+ data->num_keys -= removed_keys;
+
+ /* sanity check to see if anything is left */
+
+ if ( !data->num_keys )
+ {
+ DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
+
+ SAFE_FREE( data->keys );
+ ZERO_STRUCTP( data );
+ }
+
+ return WERR_OK;
}
/****************************************************************************
@@ -2465,11 +2602,8 @@ WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value
key_index = lookup_printerkey( &p2->data, key );
if ( key_index == -1 )
- key_index = add_new_printer_key( &p2->data, key );
+ return WERR_OK;
- if ( key_index == -1 )
- return WERR_NOMEM;
-
regval_ctr_delvalue( &p2->data.keys[key_index].values, value );
DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
@@ -2504,8 +2638,8 @@ WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, char *key, char *value,
regval_ctr_addvalue( &p2->data.keys[key_index].values, value,
type, data, real_len );
- DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], size => [%d]\n",
- key, value, real_len ));
+ DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
+ key, value, type, real_len ));
return result;
}
@@ -2569,7 +2703,7 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
* Should only be one '\' in the string returned.
*/
- str = strchr( string, '\\');
+ str = strrchr( string, '\\');
/* Put in "PrinterDriverData" is no key specified */
@@ -2598,7 +2732,7 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, data_p, size );
- DEBUG(8,("specific: [%s\\%s], len: %d\n", keyname, valuename, size));
+ DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
}
return len;
@@ -3046,7 +3180,7 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
* should not be any (if there are delete them).
*/
- delete_all_printer_data( info_ptr );
+ delete_all_printer_data( info_ptr, "" );
slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
@@ -3074,16 +3208,17 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
* the initialization save. Change it to reflect the new printer.
*/
+ if ( info.devmode ) {
ZERO_STRUCT(info.devmode->devicename);
fstrcpy(info.devmode->devicename, info_ptr->printername);
-
+ }
/*
* NT/2k does not change out the entire DeviceMode of a printer
* when changing the driver. Only the driverextra, private, &
* driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
*
- * Later e4xamination revealed that Windows NT/2k does reset the
+ * Later examination revealed that Windows NT/2k does reset the
* the printer's device mode, bit **only** when you change a
* property of the device mode such as the page orientation.
* --jerry
@@ -3095,9 +3230,8 @@ static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
free_nt_devicemode(&info_ptr->devmode);
info_ptr->devmode = info.devmode;
-
- DEBUG(10,("set_driver_init_2: Set printer [%s] init DEVMODE for driver [%s]\n",
- info_ptr->printername, info_ptr->drivername));
+ DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
+ info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
/* Add the printer data 'values' to the new printer */
@@ -3232,11 +3366,11 @@ uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
{
case 2:
{
- result=update_driver_init_2(printer.info_2);
+ result = update_driver_init_2(printer.info_2);
break;
}
default:
- result=1;
+ result = 1;
break;
}
@@ -3244,6 +3378,151 @@ uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
}
/****************************************************************************
+ Convert the printer data value, a REG_BINARY array, into an initialization
+ DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
+ got to keep the endians happy :).
+****************************************************************************/
+
+static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
+{
+ BOOL result = False;
+ prs_struct ps;
+ DEVICEMODE devmode;
+
+ ZERO_STRUCT(devmode);
+
+ prs_init(&ps, 0, ctx, UNMARSHALL);
+ ps.data_p = (char *)data;
+ ps.buffer_size = data_len;
+
+ if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
+ result = convert_devicemode("", &devmode, &nt_devmode);
+ else
+ DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
+
+ return result;
+}
+
+/****************************************************************************
+ Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
+
+ 1. Use the driver's config DLL to this UNC printername and:
+ a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
+ b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
+ 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
+
+ The last step triggers saving the "driver initialization" information for
+ this printer into the tdb. Later, new printers that use this driver will
+ have this initialization information bound to them. This simulates the
+ driver initialization, as if it had run on the Samba server (as it would
+ have done on NT).
+
+ The Win32 client side code requirement sucks! But until we can run arbitrary
+ Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
+
+ It would have been easier to use SetPrinter because all the UNMARSHALLING of
+ the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
+ about it and you will realize why. JRR 010720
+****************************************************************************/
+
+static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
+{
+ WERROR status = WERR_OK;
+ TALLOC_CTX *ctx = NULL;
+ NT_DEVICEMODE *nt_devmode = NULL;
+ NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
+
+ /*
+ * When the DEVMODE is already set on the printer, don't try to unpack it.
+ */
+ DEBUG(8,("save_driver_init_2: Enter...\n"));
+
+ if ( !printer->info_2->devmode && data_len )
+ {
+ /*
+ * Set devmode on printer info, so entire printer initialization can be
+ * saved to tdb.
+ */
+
+ if ((ctx = talloc_init()) == NULL)
+ return WERR_NOMEM;
+
+ if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ ZERO_STRUCTP(nt_devmode);
+
+ /*
+ * The DEVMODE is held in the 'data' component of the param in raw binary.
+ * Convert it to to a devmode structure
+ */
+ if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
+ DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
+ status = WERR_INVALID_PARAM;
+ goto done;
+ }
+
+ printer->info_2->devmode = nt_devmode;
+ }
+
+ /*
+ * Pack up and add (or update) the DEVMODE and any current printer data to
+ * a 'driver init' element in the tdb
+ *
+ */
+
+ if ( update_driver_init(*printer, 2) != 0 ) {
+ DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
+ status = WERR_NOMEM;
+ goto done;
+ }
+
+ /*
+ * If driver initialization info was successfully saved, set the current
+ * printer to match it. This allows initialization of the current printer
+ * as well as the driver.
+ */
+ status = mod_a_printer(*printer, 2);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
+ printer->info_2->printername));
+ }
+
+ done:
+ talloc_destroy(ctx);
+ free_nt_devicemode( &nt_devmode );
+
+ printer->info_2->devmode = tmp_devmode;
+
+ return status;
+}
+
+/****************************************************************************
+ Update the driver init info (DEVMODE and specifics) for a printer
+****************************************************************************/
+
+WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
+{
+ WERROR status = WERR_OK;
+
+ switch (level)
+ {
+ case 2:
+ {
+ status = save_driver_init_2( printer, data, data_len );
+ break;
+ }
+ default:
+ status = WERR_UNKNOWN_LEVEL;
+ break;
+ }
+
+ return status;
+}
+
+/****************************************************************************
Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
****************************************************************************/
@@ -3445,13 +3724,13 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
to a printer
****************************************************************************/
-BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i )
+BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
{
int snum;
int n_services = lp_numservices();
NT_PRINTER_INFO_LEVEL *printer = NULL;
- if ( !i )
+ if ( !info_3 )
return False;
DEBUG(5,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
@@ -3466,7 +3745,7 @@ BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i )
if ( !W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) )
continue;
- if ( !StrCaseCmp(i->name, printer->info_2->drivername) ) {
+ if ( !StrCaseCmp(info_3->name, printer->info_2->drivername) ) {
free_a_printer( &printer, 2 );
return True;
}
@@ -3488,7 +3767,7 @@ BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i )
static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
{
- char *s;
+ int i = 0;
if ( !info )
return False;
@@ -3504,16 +3783,18 @@ static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
if ( strequal(file, info->helpfile) )
return True;
-
- s = (char*) info->dependentfiles;
- if ( s ) {
- while ( *s )
- {
- if ( strequal(file, s) )
- return True;
- s += strlen(s) + 1;
- }
+ /* see of there are any dependent files to examine */
+
+ if ( !info->dependentfiles )
+ return False;
+
+ while ( *info->dependentfiles[i] )
+ {
+ if ( strequal(file, info->dependentfiles[i]) )
+ return True;
+
+ i++;
}
return False;
@@ -3525,27 +3806,20 @@ static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
input parameter from the list
*********************************************************************/
-static void trim_dependent_file( char* s )
+static void trim_dependent_file( fstring files[], int idx )
{
- char *p;
-
- /* set p to the next character string in the list */
-
- p = s + strlen( s ) + 1;
-
- /* check to see that we have another string to copy back */
- if ( *p == '\0' )
+ /* bump everything down a slot */
+
+ while( *files[idx+1] )
{
- /* loop over s copying characters from p to s */
- while ( *p!='\0' && *(p+1)!='\0' )
- *s++ = *p++;
+ fstrcpy( files[idx], files[idx+1] );
+ idx++;
}
- /* add the two trailing NULL's */
-
- *s = '\0';
- *(s+1) = '\0';
+ *files[idx] = '\0';
+
+ return;
}
/**********************************************************************
@@ -3555,8 +3829,8 @@ static void trim_dependent_file( char* s )
static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
{
- BOOL in_use = False;
- char *s;
+ BOOL in_use = False;
+ int i = 0;
if ( !src || !drv )
return False;
@@ -3565,33 +3839,43 @@ static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
if ( drv_file_in_use(src->driverpath, drv) ) {
in_use = True;
+ DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
fstrcpy( src->driverpath, "" );
}
if ( drv_file_in_use(src->datafile, drv) ) {
in_use = True;
+ DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
fstrcpy( src->datafile, "" );
}
if ( drv_file_in_use(src->configfile, drv) ) {
in_use = True;
+ DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
fstrcpy( src->configfile, "" );
}
- s = (char*)src->dependentfiles;
-
- if ( s ) {
- while ( *s )
- {
- if ( drv_file_in_use(s, drv) ) {
- in_use = True;
- trim_dependent_file( s );
- }
- else
- s += strlen(s) + 1;
- }
+ if ( drv_file_in_use(src->helpfile, drv) ) {
+ in_use = True;
+ DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
+ fstrcpy( src->helpfile, "" );
}
+
+ /* are there any dependentfiles to examine? */
+
+ if ( !src->dependentfiles )
+ return in_use;
+ while ( *src->dependentfiles[i] )
+ {
+ if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
+ in_use = True;
+ DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
+ trim_dependent_file( src->dependentfiles, i );
+ }
+ else
+ i++;
+ }
return in_use;
}
@@ -3615,59 +3899,62 @@ BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
fstring *list = NULL;
NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ if ( !info )
+ return False;
+
+ version = info->cversion;
+
/* loop over all driver versions */
DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
- for ( version=0; version<DRIVER_MAX_VERSION; version++ )
- {
- /* get the list of drivers */
+ /* get the list of drivers */
- list = NULL;
- ndrivers = get_ntdrivers(&list, info->environment, version);
+ list = NULL;
+ ndrivers = get_ntdrivers(&list, info->environment, version);
- DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
- ndrivers, info->environment, version));
+ DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
+ ndrivers, info->environment, version));
- if (ndrivers == -1)
- continue;
-
- /* check each driver for overlap in files */
+ /* check each driver for overlap in files */
- for (i=0; i<ndrivers; i++)
- {
- DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
+ for (i=0; i<ndrivers; i++)
+ {
+ DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
- ZERO_STRUCT(driver);
+ ZERO_STRUCT(driver);
- if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i],
- info->environment, version)) )
- {
- SAFE_FREE(list);
- return True;
- }
+ if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i],
+ info->environment, version)) )
+ {
+ SAFE_FREE(list);
+ return True;
+ }
- /* check if d2 uses any files from d1 */
- /* only if this is a different driver than the one being deleted */
+ /* check if d2 uses any files from d1 */
+ /* only if this is a different driver than the one being deleted */
- if ( !strequal(info->name, driver.info_3->name)
- || (info->cversion != driver.info_3->cversion) )
- {
- if ( trim_overlap_drv_files(info, driver.info_3) ) {
- free_a_printer_driver(driver, 3);
- SAFE_FREE( list );
- return True;
- }
+ if ( !strequal(info->name, driver.info_3->name) )
+ {
+ if ( trim_overlap_drv_files(info, driver.info_3) ) {
+ free_a_printer_driver(driver, 3);
+ SAFE_FREE( list );
+ return True;
}
+ }
- free_a_printer_driver(driver, 3);
- }
-
- SAFE_FREE(list);
- }
+ free_a_printer_driver(driver, 3);
+ }
+
+ SAFE_FREE(list);
DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
+ driver.info_3 = info;
+
+ if ( DEBUGLEVEL >= 20 )
+ dump_a_printer_driver( driver, 3 );
+
return False;
}
@@ -3677,17 +3964,18 @@ BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
this.
****************************************************************************/
-static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i, struct current_user *user )
+static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
{
+ int i = 0;
char *s;
connection_struct *conn;
DATA_BLOB null_pw;
NTSTATUS nt_status;
- if ( !i )
+ if ( !info_3 )
return False;
- DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", i->name, i->cversion));
+ DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
/*
* Connect to the print$ share under the same account as the
@@ -3715,49 +4003,55 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i, struct curre
/* now delete the files; must strip the '\print$' string from
fron of path */
- if ( *i->driverpath ) {
- if ( (s = strchr( &i->driverpath[1], '\\' )) != NULL ) {
+ if ( *info_3->driverpath ) {
+ if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
DEBUG(10,("deleting driverfile [%s]\n", s));
unlink_internals(conn, 0, s);
}
}
- if ( *i->configfile ) {
- if ( (s = strchr( &i->configfile[1], '\\' )) != NULL ) {
+ if ( *info_3->configfile ) {
+ if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
DEBUG(10,("deleting configfile [%s]\n", s));
unlink_internals(conn, 0, s);
}
}
- if ( *i->datafile ) {
- if ( (s = strchr( &i->datafile[1], '\\' )) != NULL ) {
+ if ( *info_3->datafile ) {
+ if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
DEBUG(10,("deleting datafile [%s]\n", s));
unlink_internals(conn, 0, s);
}
}
- if ( *i->helpfile ) {
- if ( (s = strchr( &i->helpfile[1], '\\' )) != NULL ) {
+ if ( *info_3->helpfile ) {
+ if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
DEBUG(10,("deleting helpfile [%s]\n", s));
unlink_internals(conn, 0, s);
}
}
- s = (char*)i->dependentfiles;
+ /* check if we are done removing files */
- while ( s && *s ) {
- char *file;
+ if ( info_3->dependentfiles )
+ {
+ while ( *info_3->dependentfiles[i] ) {
+ char *file;
- if ( (file = strchr( s+1, '\\' )) != NULL )
- {
- DEBUG(10,("deleting dependent file [%s]\n", file));
- unlink_internals(conn, 0, file );
- file += strlen( file ) + 1;
+ /* bypass the "\print$" portion of the path */
+
+ if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL )
+ {
+ DEBUG(10,("deleting dependent file [%s]\n", file));
+ unlink_internals(conn, 0, file );
+ }
+
+ i++;
}
-
- s = file;
}
+ unbecome_user();
+
return True;
}
@@ -3766,7 +4060,7 @@ static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i, struct curre
previously looked up.
***************************************************************************/
-static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i, struct current_user *user,
+WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
uint32 version, BOOL delete_files )
{
pstring key;
@@ -3776,14 +4070,14 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
/* delete the tdb data first */
- get_short_archi(arch, i->environment);
+ get_short_archi(arch, info_3->environment);
slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
- arch, version, i->name);
+ arch, version, info_3->name);
DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
key, delete_files ? "TRUE" : "FALSE" ));
- ctr.info_3 = i;
+ ctr.info_3 = info_3;
dump_a_printer_driver( ctr, 3 );
kbuf.dptr=key;
@@ -3793,7 +4087,7 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
dbuf = tdb_fetch( tdb_drivers, kbuf );
if ( !dbuf.dptr ) {
- DEBUG(8,("delete_printer_driver_internal: Driver unknown [%s]\n", key));
+ DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
return WERR_UNKNOWN_PRINTER_DRIVER;
}
@@ -3802,7 +4096,7 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
/* ok... the driver exists so the delete should return success */
if (tdb_delete(tdb_drivers, kbuf) == -1) {
- DEBUG (0,("delete_printer_driver_internal: fail to delete %s!\n", key));
+ DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
return WERR_ACCESS_DENIED;
}
@@ -3813,51 +4107,14 @@ static WERROR delete_printer_driver_internal( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i,
*/
if ( delete_files )
- delete_driver_files( i, user );
-
-
- DEBUG(5,("delete_printer_driver_internal: driver delete successful [%s]\n", key));
-
- return WERR_OK;
-}
-
-/****************************************************************************
- Remove a printer driver from the TDB. This assumes that the the driver was
- previously looked up.
- ***************************************************************************/
-
-WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *i, struct current_user *user,
- uint32 version, BOOL delete_files )
-{
- WERROR err;
-
- /*
- * see if we should delete all versions of this driver
- * (DRIVER_ANY_VERSION uis only set for "Windows NT x86")
- */
-
- if ( version == DRIVER_ANY_VERSION )
- {
- /* Windows NT 4.0 */
-
- err = delete_printer_driver_internal(i, user, 2, delete_files );
- if ( !W_ERROR_IS_OK(err) && (W_ERROR_V(err) != ERRunknownprinterdriver ) )
- return err;
+ delete_driver_files( info_3, user );
- /* Windows 2000/XP */
- err = delete_printer_driver_internal(i, user, 3, delete_files );
- if ( !W_ERROR_IS_OK(err) && (W_ERROR_V(err) != ERRunknownprinterdriver ) )
- return err;
+ DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
return WERR_OK;
}
- /* just delete what they asked for */
-
- return delete_printer_driver_internal(i, user, version, delete_files );
-}
-
/****************************************************************************
Store a security desc for a printer.
****************************************************************************/
diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c
index 51ebb739a3..2df846aa57 100644
--- a/source3/printing/print_cups.c
+++ b/source3/printing/print_cups.c
@@ -73,9 +73,9 @@ cups_passwd_cb(const char *prompt) /* I - Prompt */
* system.
*/
-void
-cups_printer_fn(void (*fn)(char *, char *)) /* I - Function to call */
+void cups_printer_fn(void (*fn)(char *, char *))
{
+ /* I - Function to call */
http_t *http; /* HTTP connection to server */
ipp_t *request, /* IPP Request */
*response; /* IPP Response */
@@ -665,6 +665,10 @@ cups_job_submit(int snum, struct printjob *pjob)
httpClose(http);
+ if ( ret == 0 )
+ unlink(pjob->filename);
+ /* else print_job_end will do it for us */
+
return (ret);
}
diff --git a/source3/printing/printfsp.c b/source3/printing/printfsp.c
index ff50ac47c4..8a4e7ea073 100644
--- a/source3/printing/printfsp.c
+++ b/source3/printing/printfsp.c
@@ -46,7 +46,7 @@ files_struct *print_fsp_open(connection_struct *conn, char *fname)
fstrcat(name, p);
}
- jobid = print_job_start(&current_user, SNUM(conn), name);
+ jobid = print_job_start(&current_user, SNUM(conn), name, NULL);
if (jobid == -1) {
file_free(fsp);
return NULL;
diff --git a/source3/printing/printing.c b/source3/printing/printing.c
index cb689c05d6..6474c92c69 100644
--- a/source3/printing/printing.c
+++ b/source3/printing/printing.c
@@ -132,11 +132,13 @@ static pid_t local_pid;
static int get_queue_status(int, print_status_struct *);
+/* There can be this many printing tdb's open, plus any locked ones. */
#define MAX_PRINT_DBS_OPEN 1
struct tdb_print_db {
struct tdb_print_db *next, *prev;
TDB_CONTEXT *tdb;
+ int ref_count;
fstring printer_name;
};
@@ -149,32 +151,45 @@ static struct tdb_print_db *print_db_head;
static struct tdb_print_db *get_print_db_byname(const char *printername)
{
- struct tdb_print_db *p, *last_entry;
+ struct tdb_print_db *p = NULL, *last_entry = NULL;
int num_open = 0;
pstring printdb_path;
for (p = print_db_head, last_entry = print_db_head; p; p = p->next) {
if (p->tdb && strequal(p->printer_name, printername)) {
DLIST_PROMOTE(print_db_head, p);
+ p->ref_count++;
return p;
}
num_open++;
last_entry = p;
}
+
/* Not found. */
if (num_open >= MAX_PRINT_DBS_OPEN) {
- /* Recycle the last entry. */
+ /* Try and recycle the last entry. */
DLIST_PROMOTE(print_db_head, last_entry);
- if (print_db_head->tdb) {
- if (tdb_close(print_db_head->tdb)) {
- DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n",
- print_db_head->printer_name ));
- return NULL;
+
+ for (p = print_db_head; p; p = p->next) {
+ if (p->ref_count)
+ continue;
+ if (p->tdb) {
+ if (tdb_close(print_db_head->tdb)) {
+ DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n",
+ print_db_head->printer_name ));
+ return NULL;
+ }
}
+ ZERO_STRUCTP(p);
+ break;
}
- p = print_db_head;
- ZERO_STRUCTP(p);
- } else {
+ if (p) {
+ DLIST_PROMOTE(print_db_head, p);
+ p = print_db_head;
+ }
+ }
+
+ if (!p) {
/* Create one. */
p = (struct tdb_print_db *)malloc(sizeof(struct tdb_print_db));
if (!p) {
@@ -201,9 +216,16 @@ static struct tdb_print_db *get_print_db_byname(const char *printername)
return NULL;
}
fstrcpy(p->printer_name, printername);
+ p->ref_count++;
return p;
}
+static void release_print_db( struct tdb_print_db *pdb)
+{
+ pdb->ref_count--;
+ SMB_ASSERT(pdb->ref_count >= 0);
+}
+
/****************************************************************************
Initialise the printing backend. Called once at startup.
Does not survive a fork
@@ -235,7 +257,10 @@ BOOL print_backend_init(void)
pdb = get_print_db_byname(lp_const_servicename(snum));
if (!pdb)
continue;
- tdb_lock_bystring(pdb->tdb, sversion);
+ if (tdb_lock_bystring(pdb->tdb, sversion) == -1) {
+ DEBUG(0,("print_backend_init: Failed to open printer %s database\n", lp_const_servicename(snum) ));
+ return False;
+ }
if (tdb_fetch_int32(pdb->tdb, sversion) != PRINT_DATABASE_VERSION) {
tdb_traverse(pdb->tdb, tdb_traverse_delete_fn, NULL);
tdb_store_int32(pdb->tdb, sversion, PRINT_DATABASE_VERSION);
@@ -286,25 +311,74 @@ static TDB_DATA print_key(uint32 jobid)
return ret;
}
+/***********************************************************************
+ unpack a pjob from a tdb buffer
+***********************************************************************/
+
+int unpack_pjob( char* buf, int buflen, struct printjob *pjob )
+{
+ int len = 0;
+ int used;
+
+ if ( !buf || !pjob )
+ return -1;
+
+ len += tdb_unpack(buf+len, buflen-len, "dddddddddffff",
+ &pjob->pid,
+ &pjob->sysjob,
+ &pjob->fd,
+ &pjob->starttime,
+ &pjob->status,
+ &pjob->size,
+ &pjob->page_count,
+ &pjob->spooled,
+ &pjob->smbjob,
+ pjob->filename,
+ pjob->jobname,
+ pjob->user,
+ pjob->queuename);
+
+ if ( len == -1 )
+ return -1;
+
+ if ( (used = unpack_devicemode(&pjob->nt_devmode, buf+len, buflen-len)) == -1 )
+ return -1;
+
+ len += used;
+
+ return len;
+
+}
+
/****************************************************************************
Useful function to find a print job in the database.
****************************************************************************/
static struct printjob *print_job_find(int snum, uint32 jobid)
{
- static struct printjob pjob;
- TDB_DATA ret;
- struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+ static struct printjob pjob;
+ TDB_DATA ret;
+ struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+
if (!pdb)
return NULL;
ret = tdb_fetch(pdb->tdb, print_key(jobid));
- if (!ret.dptr || ret.dsize != sizeof(pjob))
- return NULL;
+ release_print_db(pdb);
- memcpy(&pjob, ret.dptr, sizeof(pjob));
- SAFE_FREE(ret.dptr);
+ if (!ret.dptr)
+ return NULL;
+
+ if ( pjob.nt_devmode )
+ free_nt_devicemode( &pjob.nt_devmode );
+
+ ZERO_STRUCT( pjob );
+
+ if ( unpack_pjob( ret.dptr, ret.dsize, &pjob ) == -1 )
+ return NULL;
+
+ SAFE_FREE(ret.dptr);
return &pjob;
}
@@ -315,9 +389,13 @@ static uint32 sysjob_to_jobid_value;
static int unixjob_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key,
TDB_DATA data, void *state)
{
- struct printjob *pjob = (struct printjob *)data.dptr;
+ struct printjob *pjob;
int *sysjob = (int *)state;
+ if (!data.dptr || data.dsize == 0)
+ return 0;
+
+ pjob = (struct printjob *)data.dptr;
if (key.dsize != sizeof(uint32))
return 0;
@@ -350,6 +428,7 @@ uint32 sysjob_to_jobid(int unix_jobid)
pdb = get_print_db_byname(lp_const_servicename(snum));
if (pdb)
tdb_traverse(pdb->tdb, unixjob_traverse_fn, &unix_jobid);
+ release_print_db(pdb);
if (sysjob_to_jobid_value != (uint32)-1)
return sysjob_to_jobid_value;
}
@@ -434,9 +513,12 @@ static void pjob_store_notify(int snum, uint32 jobid, struct printjob *old_data,
static BOOL pjob_store(int snum, uint32 jobid, struct printjob *pjob)
{
- TDB_DATA old_data, new_data;
- BOOL ret;
- struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+ TDB_DATA old_data, new_data;
+ BOOL ret = False;
+ struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+ char *buf = NULL;
+ int len, newlen, buflen;
+
if (!pdb)
return False;
@@ -445,20 +527,63 @@ static BOOL pjob_store(int snum, uint32 jobid, struct printjob *pjob)
old_data = tdb_fetch(pdb->tdb, print_key(jobid));
+ /* Doh! Now we have to pack/unpack data since the NT_DEVICEMODE was added */
+
+ newlen = 0;
+
+ do {
+ len = 0;
+ buflen = newlen;
+ len += tdb_pack(buf+len, buflen-len, "dddddddddffff",
+ pjob->pid,
+ pjob->sysjob,
+ pjob->fd,
+ pjob->starttime,
+ pjob->status,
+ pjob->size,
+ pjob->page_count,
+ pjob->spooled,
+ pjob->smbjob,
+ pjob->filename,
+ pjob->jobname,
+ pjob->user,
+ pjob->queuename);
+
+ len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len);
+
+ if (buflen != len)
+ {
+ char *tb;
+
+ tb = (char *)Realloc(buf, len);
+ if (!tb) {
+ DEBUG(0,("pjob_store: failed to enlarge buffer!\n"));
+ goto done;
+ }
+ else
+ buf = tb;
+ newlen = len;
+ }
+ }
+ while ( buflen != len );
+
+
/* Store new data */
- new_data.dptr = (void *)pjob;
- new_data.dsize = sizeof(*pjob);
+ new_data.dptr = buf;
+ new_data.dsize = len;
ret = (tdb_store(pdb->tdb, print_key(jobid), new_data, TDB_REPLACE) == 0);
+ release_print_db(pdb);
+
/* Send notify updates for what has changed */
- if (ret && (old_data.dsize == 0 || old_data.dsize == sizeof(*pjob))) {
- pjob_store_notify(
- snum, jobid, (struct printjob *)old_data.dptr,
- (struct printjob *)new_data.dptr);
- free(old_data.dptr);
- }
+ if ( ret && (old_data.dsize == 0 || old_data.dsize == sizeof(*pjob)) )
+ pjob_store_notify( snum, jobid, (struct printjob *)old_data.dptr, pjob );
+
+done:
+ SAFE_FREE( old_data.dptr );
+ SAFE_FREE( buf );
return ret;
}
@@ -479,6 +604,7 @@ static void pjob_delete(int snum, uint32 jobid)
if (!pjob) {
DEBUG(5, ("pjob_delete(): we were asked to delete nonexistent job %u\n",
(unsigned int)jobid));
+ release_print_db(pdb);
return;
}
@@ -499,6 +625,7 @@ static void pjob_delete(int snum, uint32 jobid)
/* Remove from printing.tdb */
tdb_delete(pdb->tdb, print_key(jobid));
+ release_print_db(pdb);
rap_jobid_delete(snum, jobid);
}
@@ -569,10 +696,14 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
uint32 jobid;
int i;
- if (data.dsize != sizeof(pjob) || key.dsize != sizeof(jobid))
+ if ( key.dsize != sizeof(jobid) )
return 0;
+
memcpy(&jobid, key.dptr, sizeof(jobid));
- memcpy(&pjob, data.dptr, sizeof(pjob));
+ if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
+ return 0;
+ free_nt_devicemode( &pjob.nt_devmode );
+
if (ts->snum != lp_servicenumber(pjob.queuename)) {
/* this isn't for the queue we are looking at - this cannot happen with the split tdb's. JRA */
@@ -651,6 +782,7 @@ static void print_cache_flush(int snum)
return;
slprintf(key, sizeof(key)-1, "CACHE/%s", printername);
tdb_store_int32(pdb->tdb, key, -1);
+ release_print_db(pdb);
}
/****************************************************************************
@@ -671,6 +803,7 @@ static pid_t get_updating_pid(fstring printer_name)
key.dsize = strlen(keystr);
data = tdb_fetch(pdb->tdb, key);
+ release_print_db(pdb);
if (!data.dptr || data.dsize != sizeof(pid_t))
return (pid_t)-1;
@@ -705,6 +838,7 @@ static void set_updating_pid(const fstring printer_name, BOOL delete)
if (delete) {
tdb_delete(pdb->tdb, key);
+ release_print_db(pdb);
return;
}
@@ -712,6 +846,7 @@ static void set_updating_pid(const fstring printer_name, BOOL delete)
data.dsize = sizeof(pid_t);
tdb_store(pdb->tdb, key, data, TDB_REPLACE);
+ release_print_db(pdb);
}
/****************************************************************************
@@ -740,13 +875,19 @@ static void print_queue_update(int snum)
* This is essentially a mutex on the update.
*/
- if (get_updating_pid(printer_name) != -1)
+ if (get_updating_pid(printer_name) != -1) {
+ release_print_db(pdb);
return;
+ }
/* Lock the queue for the database update */
slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", printer_name);
- tdb_lock_bystring(pdb->tdb, keystr);
+ if (tdb_lock_bystring(pdb->tdb, keystr) == -1) {
+ DEBUG(0,("print_queue_update: Failed to lock printer %s database\n", printer_name));
+ release_print_db(pdb);
+ return;
+ }
/*
* Ensure that no one else got in here.
@@ -759,6 +900,7 @@ static void print_queue_update(int snum)
* Someone else is doing the update, exit.
*/
tdb_unlock_bystring(pdb->tdb, keystr);
+ release_print_db(pdb);
return;
}
@@ -865,6 +1007,7 @@ static void print_queue_update(int snum)
/* Delete our pid from the db. */
set_updating_pid(printer_name, True);
+ release_print_db(pdb);
}
/****************************************************************************
@@ -874,9 +1017,13 @@ static void print_queue_update(int snum)
BOOL print_job_exists(int snum, uint32 jobid)
{
struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+ BOOL ret;
+
if (!pdb)
return False;
- return tdb_exists(pdb->tdb, print_key(jobid));
+ ret = tdb_exists(pdb->tdb, print_key(jobid));
+ release_print_db(pdb);
+ return ret;
}
/****************************************************************************
@@ -908,6 +1055,23 @@ char *print_job_fname(int snum, uint32 jobid)
return pjob->filename;
}
+
+/****************************************************************************
+ Give the filename used for a jobid.
+ Only valid for the process doing the spooling and when the job
+ has not been spooled.
+****************************************************************************/
+
+NT_DEVICEMODE *print_job_devmode(int snum, uint32 jobid)
+{
+ struct printjob *pjob = print_job_find(snum, jobid);
+
+ if ( !pjob )
+ return NULL;
+
+ return pjob->nt_devmode;
+}
+
/****************************************************************************
Set the place in the queue for a job.
****************************************************************************/
@@ -1000,8 +1164,11 @@ static BOOL is_owner(struct current_user *user, int snum, uint32 jobid)
BOOL print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR *errcode)
{
- BOOL owner;
+ BOOL owner, deleted;
+ char *fname;
+ *errcode = WERR_OK;
+
owner = is_owner(user, snum, jobid);
/* Check access against security descriptor or whether the user
@@ -1014,15 +1181,40 @@ BOOL print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR
return False;
}
- if (!print_job_delete1(snum, jobid))
+ /*
+ * get the spooled filename of the print job
+ * if this works, then the file has not been spooled
+ * to the underlying print system. Just delete the
+ * spool file & return.
+ */
+
+ if ( (fname = print_job_fname( snum, jobid )) != NULL )
+ {
+ /* remove the spool file */
+ DEBUG(10,("print_job_delete: Removing spool file [%s]\n", fname ));
+ if ( unlink( fname ) == -1 ) {
+ *errcode = map_werror_from_unix(errno);
+ return False;
+ }
+
+ return True;
+ }
+
+ if (!print_job_delete1(snum, jobid)) {
+ *errcode = WERR_ACCESS_DENIED;
return False;
+ }
/* force update the database and say the delete failed if the
job still exists */
print_queue_update(snum);
+
+ deleted = !print_job_exists(snum, jobid);
+ if ( !deleted )
+ *errcode = WERR_ACCESS_DENIED;
- return !print_job_exists(snum, jobid);
+ return deleted;
}
/****************************************************************************
@@ -1161,8 +1353,10 @@ static BOOL print_cache_expired(int snum)
DEBUG(3, ("print cache expired for queue %s \
(last_qscan_time = %d, time now = %d, qcachetime = %d)\n", printername,
(int)last_qscan_time, (int)time_now, (int)lp_lpqcachetime() ));
+ release_print_db(pdb);
return True;
}
+ release_print_db(pdb);
return False;
}
@@ -1184,6 +1378,7 @@ static int get_queue_status(int snum, print_status_struct *status)
key.dptr = keystr;
key.dsize = strlen(keystr);
data = tdb_fetch(pdb->tdb, key);
+ release_print_db(pdb);
if (data.dptr) {
if (data.dsize == sizeof(print_status_struct)) {
memcpy(status, data.dptr, sizeof(print_status_struct));
@@ -1214,44 +1409,11 @@ int print_queue_length(int snum, print_status_struct *pstatus)
return len;
}
-/****************************************************************************
- Determine the number of jobs in all queues. This is very expensive. Don't
- call ! JRA.
-****************************************************************************/
-
-static int get_total_jobs(void)
-{
- int total_jobs = 0;
- int snum;
- int services = lp_numservices();
-
- for (snum = 0; snum < services; snum++) {
- struct tdb_print_db *pdb;
- int jobs;
-
- if (!lp_print_ok(snum))
- continue;
-
- pdb = get_print_db_byname(lp_const_servicename(snum));
- if (!pdb)
- continue;
-
- /* make sure the database is up to date */
- if (print_cache_expired(snum))
- print_queue_update(snum);
-
- jobs = tdb_fetch_int32(pdb->tdb, "INFO/total_jobs");
- if (jobs > 0)
- total_jobs += jobs;
- }
- return total_jobs;
-}
-
/***************************************************************************
Start spooling a job - return the jobid.
***************************************************************************/
-uint32 print_job_start(struct current_user *user, int snum, char *jobname)
+uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DEVICEMODE *nt_devmode )
{
uint32 jobid;
char *path;
@@ -1261,6 +1423,7 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
int njobs = 0;
const char *printername = lp_const_servicename(snum);
struct tdb_print_db *pdb = get_print_db_byname(printername);
+ BOOL pdb_locked = False;
errno = 0;
@@ -1269,11 +1432,13 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) {
DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
+ release_print_db(pdb);
return (uint32)-1;
}
if (!print_time_access_check(snum)) {
DEBUG(3, ("print_job_start: job start denied by time check\n"));
+ release_print_db(pdb);
return (uint32)-1;
}
@@ -1285,6 +1450,7 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
if (sys_fsusage(path, &dspace, &dsize) == 0 &&
dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) {
DEBUG(3, ("print_job_start: disk space check failed.\n"));
+ release_print_db(pdb);
errno = ENOSPC;
return (uint32)-1;
}
@@ -1293,6 +1459,7 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
/* for autoloaded printers, check that the printcap entry still exists */
if (lp_autoloaded(snum) && !pcap_printername_ok(lp_const_servicename(snum), NULL)) {
DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_const_servicename(snum) ));
+ release_print_db(pdb);
errno = ENOENT;
return (uint32)-1;
}
@@ -1301,41 +1468,19 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
if (lp_maxprintjobs(snum) && (njobs = print_queue_length(snum,NULL)) > lp_maxprintjobs(snum)) {
DEBUG(3, ("print_job_start: number of jobs (%d) larger than max printjobs per queue (%d).\n",
njobs, lp_maxprintjobs(snum) ));
+ release_print_db(pdb);
errno = ENOSPC;
return (uint32)-1;
}
- /* Insure the maximum print jobs in the system is not violated */
- if (lp_totalprintjobs() && get_total_jobs() > lp_totalprintjobs()) {
- DEBUG(3, ("print_job_start: number of jobs (%d) larger than max printjobs per system (%d).\n",
- njobs, lp_totalprintjobs() ));
- errno = ENOSPC;
+ /* Lock the database */
+ if (tdb_lock_bystring(pdb->tdb, "INFO/nextjob") == -1) {
+ DEBUG(0,("print_job_start: failed to lock printing database %s\n", printername ));
+ release_print_db(pdb);
return (uint32)-1;
}
- /* create the database entry */
- ZERO_STRUCT(pjob);
- pjob.pid = local_pid;
- pjob.sysjob = -1;
- pjob.fd = -1;
- pjob.starttime = time(NULL);
- pjob.status = LPQ_SPOOLING;
- pjob.size = 0;
- pjob.spooled = False;
- pjob.smbjob = True;
-
- fstrcpy(pjob.jobname, jobname);
-
- if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
- fstrcpy(pjob.user, vuser->user.smb_name);
- } else {
- fstrcpy(pjob.user, uidtoname(user->uid));
- }
-
- fstrcpy(pjob.queuename, lp_const_servicename(snum));
-
- /* lock the database */
- tdb_lock_bystring(pdb->tdb, "INFO/nextjob");
+ pdb_locked = True;
next_jobid = tdb_fetch_int32(pdb->tdb, "INFO/nextjob");
if (next_jobid == -1)
@@ -1345,19 +1490,61 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
if (!print_job_exists(snum, jobid))
break;
}
- if (jobid == next_jobid || !pjob_store(snum, jobid, &pjob)) {
- DEBUG(3, ("print_job_start: either jobid (%d)==next_jobid(%d) or pjob_store failed.\n",
+
+ if (jobid == next_jobid) {
+ DEBUG(3, ("print_job_start: jobid (%d)==next_jobid(%d).\n",
jobid, next_jobid ));
jobid = -1;
goto fail;
}
+ /* Store a dummy placeholder. This must be quick as we have the lock. */
+ {
+ TDB_DATA dum;
+ dum.dptr = NULL;
+ dum.dsize = 0;
+ if (tdb_store(pdb->tdb, print_key(jobid), dum, TDB_INSERT) == -1) {
+ DEBUG(3, ("print_job_start: jobid (%d) failed to store placeholder.\n",
+ jobid ));
+ jobid = -1;
+ goto fail;
+ }
+ }
+
if (tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid)==-1) {
DEBUG(3, ("print_job_start: failed to store INFO/nextjob.\n"));
jobid = -1;
goto fail;
}
+ /* We've finished with the INFO/nextjob lock. */
+ tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+ pdb_locked = False;
+
+ /* create the database entry */
+
+ ZERO_STRUCT(pjob);
+
+ pjob.pid = local_pid;
+ pjob.sysjob = -1;
+ pjob.fd = -1;
+ pjob.starttime = time(NULL);
+ pjob.status = LPQ_SPOOLING;
+ pjob.size = 0;
+ pjob.spooled = False;
+ pjob.smbjob = True;
+ pjob.nt_devmode = nt_devmode;
+
+ fstrcpy(pjob.jobname, jobname);
+
+ if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
+ fstrcpy(pjob.user, vuser->user.smb_name);
+ } else {
+ fstrcpy(pjob.user, uidtoname(user->uid));
+ }
+
+ fstrcpy(pjob.queuename, lp_const_servicename(snum));
+
/* we have a job entry - now create the spool file */
slprintf(pjob.filename, sizeof(pjob.filename)-1, "%s/%s%.8u.XXXXXX",
path, PRINT_SPOOL_PREFIX, (unsigned int)jobid);
@@ -1378,7 +1565,7 @@ to open spool file %s.\n", pjob.filename));
pjob_store(snum, jobid, &pjob);
- tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+ release_print_db(pdb);
/*
* If the printer is marked as postscript output a leading
@@ -1397,7 +1584,9 @@ to open spool file %s.\n", pjob.filename));
if (jobid != -1)
pjob_delete(snum, jobid);
- tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+ if (pdb_locked)
+ tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+ release_print_db(pdb);
DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) ));
return -1;
@@ -1503,10 +1692,16 @@ static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *
int i;
uint32 jobid;
- if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int))
+ /* sanity checks */
+
+ if ( key.dsize != sizeof(jobid) )
return 0;
+
memcpy(&jobid, key.dptr, sizeof(jobid));
- memcpy(&pjob, data.dptr, sizeof(pjob));
+
+ if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
+ return 0;
+ free_nt_devicemode( &pjob.nt_devmode );
/* maybe it isn't for this queue */
if (ts->snum != lp_servicenumber(pjob.queuename))
@@ -1545,10 +1740,17 @@ static int traverse_count_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data,
struct printjob pjob;
uint32 jobid;
- if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int))
+ /* sanity checks */
+
+ if ( key.dsize != sizeof(jobid) )
return 0;
+
memcpy(&jobid, key.dptr, sizeof(jobid));
- memcpy(&pjob, data.dptr, sizeof(pjob));
+
+ if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
+ return 0;
+
+ free_nt_devicemode( &pjob.nt_devmode );
/* maybe it isn't for this queue - this cannot happen with the tdb/printer code. JRA */
if (ts->snum != lp_servicenumber(pjob.queuename))
@@ -1630,13 +1832,17 @@ int print_queue_status(int snum,
tdb_traverse(pdb->tdb, traverse_count_fn_queue, (void *)&tsc);
- if (tsc.count == 0)
+ if (tsc.count == 0) {
+ release_print_db(pdb);
return 0;
+ }
/* Allocate the queue size. */
if ((tstruct.queue = (print_queue_struct *)
- malloc(sizeof(print_queue_struct)*tsc.count)) == NULL)
+ malloc(sizeof(print_queue_struct)*tsc.count)) == NULL) {
+ release_print_db(pdb);
return 0;
+ }
/*
* Fill in the queue.
@@ -1648,6 +1854,7 @@ int print_queue_status(int snum,
tstruct.snum = snum;
tdb_traverse(pdb->tdb, traverse_fn_queue, (void *)&tstruct);
+ release_print_db(pdb);
/* Sort the queue by submission time otherwise they are displayed
in hash order. */