return False;
}
-static void rap_jobid_delete(const char* sharename, uint32 jobid)
+void rap_jobid_delete(const char* sharename, uint32 jobid)
{
TDB_DATA key, data;
uint16 rap_jobid;
Allocate a jobid. Hold the lock for as short a time as possible.
***************************************************************************/
-static bool allocate_print_jobid(struct tdb_print_db *pdb, int snum, const char *sharename, uint32 *pjobid)
+static WERROR allocate_print_jobid(struct tdb_print_db *pdb, int snum,
+ const char *sharename, uint32 *pjobid)
{
int i;
uint32 jobid;
+ enum TDB_ERROR terr;
+ int ret;
*pjobid = (uint32)-1;
for (i = 0; i < 3; i++) {
/* Lock the database - only wait 20 seconds. */
- if (tdb_lock_bystring_with_timeout(pdb->tdb, "INFO/nextjob", 20) == -1) {
- DEBUG(0,("allocate_print_jobid: failed to lock printing database %s\n", sharename));
- return False;
+ ret = tdb_lock_bystring_with_timeout(pdb->tdb,
+ "INFO/nextjob", 20);
+ if (ret == -1) {
+ DEBUG(0, ("allocate_print_jobid: "
+ "Failed to lock printing database %s\n",
+ sharename));
+ terr = tdb_error(pdb->tdb);
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
if (!tdb_fetch_uint32(pdb->tdb, "INFO/nextjob", &jobid)) {
- if (tdb_error(pdb->tdb) != TDB_ERR_NOEXIST) {
- DEBUG(0, ("allocate_print_jobid: failed to fetch INFO/nextjob for print queue %s\n",
- sharename));
+ terr = tdb_error(pdb->tdb);
+ if (terr != TDB_ERR_NOEXIST) {
+ DEBUG(0, ("allocate_print_jobid: "
+ "Failed to fetch INFO/nextjob "
+ "for print queue %s\n", sharename));
tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
- return False;
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
- DEBUG(10,("allocate_print_jobid: no existing jobid in %s\n", sharename));
+ DEBUG(10, ("allocate_print_jobid: "
+ "No existing jobid in %s\n", sharename));
jobid = 0;
}
- DEBUG(10,("allocate_print_jobid: read jobid %u from %s\n", jobid, sharename));
+ DEBUG(10, ("allocate_print_jobid: "
+ "Read jobid %u from %s\n", jobid, sharename));
jobid = NEXT_JOBID(jobid);
- if (tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid)==-1) {
- DEBUG(3, ("allocate_print_jobid: failed to store INFO/nextjob.\n"));
+ ret = tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid);
+ if (ret == -1) {
+ terr = tdb_error(pdb->tdb);
+ DEBUG(3, ("allocate_print_jobid: "
+ "Failed to store INFO/nextjob.\n"));
tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
- return False;
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
/* We've finished with the INFO/nextjob lock. */
if (!print_job_exists(sharename, jobid)) {
break;
}
- DEBUG(10,("allocate_print_jobid: found jobid %u in %s\n", jobid, sharename));
+ DEBUG(10, ("allocate_print_jobid: "
+ "Found jobid %u in %s\n", jobid, sharename));
}
if (i > 2) {
- DEBUG(0, ("allocate_print_jobid: failed to allocate a print job for queue %s\n",
- sharename));
+ DEBUG(0, ("allocate_print_jobid: "
+ "Failed to allocate a print job for queue %s\n",
+ sharename));
/* Probably full... */
- errno = ENOSPC;
- return False;
+ return WERR_NO_SPOOL_SPACE;
}
/* Store a dummy placeholder. */
dum.dsize = 0;
if (tdb_store(pdb->tdb, print_key(jobid, &tmp), dum,
TDB_INSERT) == -1) {
- DEBUG(3, ("allocate_print_jobid: jobid (%d) failed to store placeholder.\n",
- jobid ));
- return False;
+ DEBUG(3, ("allocate_print_jobid: "
+ "jobid (%d) failed to store placeholder.\n",
+ jobid ));
+ terr = tdb_error(pdb->tdb);
+ return ntstatus_to_werror(map_nt_error_from_tdb(terr));
}
}
*pjobid = jobid;
- return True;
+ return WERR_OK;
}
/***************************************************************************
data) == 0);
}
+
/***************************************************************************
- Start spooling a job - return the jobid.
+ Do all checks needed to determine if we can start a job.
***************************************************************************/
-uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
- const char *jobname, struct spoolss_DeviceMode *devmode )
+static WERROR print_job_checks(struct auth_serversupplied_info *server_info,
+ int snum, int *njobs)
{
- uint32 jobid;
- char *path;
- struct printjob pjob;
const char *sharename = lp_const_servicename(snum);
- struct tdb_print_db *pdb = get_print_db_byname(sharename);
- int njobs;
-
- errno = 0;
-
- if (!pdb)
- return (uint32)-1;
+ uint64_t dspace, dsize;
+ uint64_t minspace;
+ int ret;
if (!print_access_check(server_info, snum, PRINTER_ACCESS_USE)) {
- DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
- release_print_db(pdb);
- return (uint32)-1;
+ DEBUG(3, ("print_job_checks: "
+ "job start denied by security descriptor\n"));
+ return WERR_ACCESS_DENIED;
}
- if (!print_time_access_check(lp_servicename(snum))) {
- DEBUG(3, ("print_job_start: job start denied by time check\n"));
- release_print_db(pdb);
- return (uint32)-1;
+ if (!print_time_access_check(server_info, sharename)) {
+ DEBUG(3, ("print_job_checks: "
+ "job start denied by time check\n"));
+ return WERR_ACCESS_DENIED;
}
- path = lp_pathname(snum);
-
/* see if we have sufficient disk space */
if (lp_minprintspace(snum)) {
- uint64_t dspace, dsize;
- if (sys_fsusage(path, &dspace, &dsize) == 0 &&
- dspace < 2*(uint64_t)lp_minprintspace(snum)) {
- DEBUG(3, ("print_job_start: disk space check failed.\n"));
- release_print_db(pdb);
- errno = ENOSPC;
- return (uint32)-1;
+ minspace = lp_minprintspace(snum);
+ ret = sys_fsusage(lp_pathname(snum), &dspace, &dsize);
+ if (ret == 0 && dspace < 2*minspace) {
+ DEBUG(3, ("print_job_checks: "
+ "disk space check failed.\n"));
+ return WERR_NO_SPOOL_SPACE;
}
}
/* for autoloaded printers, check that the printcap entry still exists */
- if (lp_autoloaded(snum) && !pcap_printername_ok(lp_const_servicename(snum))) {
- DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_const_servicename(snum) ));
- release_print_db(pdb);
- errno = ENOENT;
- return (uint32)-1;
+ if (lp_autoloaded(snum) && !pcap_printername_ok(sharename)) {
+ DEBUG(3, ("print_job_checks: printer name %s check failed.\n",
+ sharename));
+ return WERR_ACCESS_DENIED;
}
/* Insure the maximum queue size is not violated */
- if ((njobs = print_queue_length(snum,NULL)) > lp_maxprintjobs(snum)) {
- DEBUG(3, ("print_job_start: Queue %s number of jobs (%d) larger than max printjobs per queue (%d).\n",
- sharename, njobs, lp_maxprintjobs(snum) ));
+ *njobs = print_queue_length(snum, NULL);
+ if (*njobs > lp_maxprintjobs(snum)) {
+ DEBUG(3, ("print_job_checks: Queue %s number of jobs (%d) "
+ "larger than max printjobs per queue (%d).\n",
+ sharename, *njobs, lp_maxprintjobs(snum)));
+ return WERR_NO_SPOOL_SPACE;
+ }
+
+ return WERR_OK;
+}
+
+/***************************************************************************
+ Create a job file.
+***************************************************************************/
+
+static WERROR print_job_spool_file(int snum, uint32_t jobid,
+ const char *output_file,
+ struct printjob *pjob)
+{
+ WERROR werr;
+ SMB_STRUCT_STAT st;
+ const char *path;
+ int len;
+
+ /* if this file is within the printer path, it means that smbd
+ * is spooling it and will pass us control when it is finished.
+ * Verify that the file name is ok, within path, and it is
+ * already already there */
+ if (output_file) {
+ path = lp_pathname(snum);
+ len = strlen(path);
+ if (strncmp(output_file, path, len) == 0 &&
+ (output_file[len - 1] == '/' || output_file[len] == '/')) {
+
+ /* verify path is not too long */
+ if (strlen(output_file) >= sizeof(pjob->filename)) {
+ return WERR_INVALID_NAME;
+ }
+
+ /* verify that the file exists */
+ if (sys_stat(output_file, &st, false) != 0) {
+ return WERR_INVALID_NAME;
+ }
+
+ fstrcpy(pjob->filename, output_file);
+
+ DEBUG(3, ("print_job_spool_file:"
+ "External spooling activated"));
+
+ /* we do not open the file until spooling is done */
+ pjob->fd = -1;
+ pjob->status = PJOB_SMBD_SPOOLING;
+
+ return WERR_OK;
+ }
+ }
+
+ slprintf(pjob->filename, sizeof(pjob->filename)-1,
+ "%s/%s%.8u.XXXXXX", lp_pathname(snum),
+ PRINT_SPOOL_PREFIX, (unsigned int)jobid);
+ pjob->fd = mkstemp(pjob->filename);
+
+ if (pjob->fd == -1) {
+ werr = map_werror_from_unix(errno);
+ if (W_ERROR_EQUAL(werr, WERR_ACCESS_DENIED)) {
+ /* Common setup error, force a report. */
+ DEBUG(0, ("print_job_spool_file: "
+ "insufficient permissions to open spool "
+ "file %s.\n", pjob->filename));
+ } else {
+ /* Normal case, report at level 3 and above. */
+ DEBUG(3, ("print_job_spool_file: "
+ "can't open spool file %s\n",
+ pjob->filename));
+ }
+ return werr;
+ }
+
+ return WERR_OK;
+}
+
+/***************************************************************************
+ Start spooling a job - return the jobid.
+***************************************************************************/
+
+WERROR print_job_start(struct auth_serversupplied_info *server_info,
+ int snum, const char *docname, const char *filename,
+ struct spoolss_DeviceMode *devmode, uint32_t *_jobid)
+{
+ uint32_t jobid;
+ char *path;
+ struct printjob pjob;
+ const char *sharename = lp_const_servicename(snum);
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ int njobs;
+ WERROR werr;
+
+ if (!pdb) {
+ return WERR_INTERNAL_DB_CORRUPTION;
+ }
+
+ path = lp_pathname(snum);
+
+ werr = print_job_checks(server_info, snum, &njobs);
+ if (!W_ERROR_IS_OK(werr)) {
release_print_db(pdb);
- errno = ENOSPC;
- return (uint32)-1;
+ return werr;
}
- DEBUG(10,("print_job_start: Queue %s number of jobs (%d), max printjobs = %d\n",
- sharename, njobs, lp_maxprintjobs(snum) ));
+ DEBUG(10, ("print_job_start: "
+ "Queue %s number of jobs (%d), max printjobs = %d\n",
+ sharename, njobs, lp_maxprintjobs(snum)));
- if (!allocate_print_jobid(pdb, snum, sharename, &jobid))
+ werr = allocate_print_jobid(pdb, snum, sharename, &jobid);
+ if (!W_ERROR_IS_OK(werr)) {
goto fail;
+ }
/* create the database entry */
pjob.smbjob = True;
pjob.devmode = devmode;
- fstrcpy(pjob.jobname, jobname);
+ fstrcpy(pjob.jobname, docname);
fstrcpy(pjob.user, lp_printjob_username(snum));
standard_sub_advanced(sharename, server_info->sanitized_username,
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);
- pjob.fd = mkstemp(pjob.filename);
-
- if (pjob.fd == -1) {
- if (errno == EACCES) {
- /* Common setup error, force a report. */
- DEBUG(0, ("print_job_start: insufficient permissions \
-to open spool file %s.\n", pjob.filename));
- } else {
- /* Normal case, report at level 3 and above. */
- DEBUG(3, ("print_job_start: can't open spool file %s,\n", pjob.filename));
- DEBUGADD(3, ("errno = %d (%s).\n", errno, strerror(errno)));
- }
+ werr = print_job_spool_file(snum, jobid, filename, &pjob);
+ if (!W_ERROR_IS_OK(werr)) {
goto fail;
}
release_print_db(pdb);
- return jobid;
+ *_jobid = jobid;
+ return WERR_OK;
- fail:
- if (jobid != -1)
+fail:
+ if (jobid != -1) {
pjob_delete(sharename, jobid);
+ }
release_print_db(pdb);
- DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) ));
- return (uint32)-1;
+ DEBUG(3, ("print_job_start: returning fail. "
+ "Error = %s\n", win_errstr(werr)));
+ return werr;
}
/****************************************************************************
error.
****************************************************************************/
-bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
+NTSTATUS print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
{
const char* sharename = lp_const_servicename(snum);
struct printjob *pjob;
int ret;
SMB_STRUCT_STAT sbuf;
struct printif *current_printif = get_printer_fns( snum );
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
pjob = print_job_find(sharename, jobid);
- if (!pjob)
- return False;
+ if (!pjob) {
+ return NT_STATUS_PRINT_CANCELLED;
+ }
- if (pjob->spooled || pjob->pid != sys_getpid())
- return False;
+ if (pjob->spooled || pjob->pid != sys_getpid()) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) {
+ if (pjob->status == PJOB_SMBD_SPOOLING) {
+ /* take over the file now, smbd is done */
+ if (sys_stat(pjob->filename, &sbuf, false) != 0) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(3, ("print_job_end: "
+ "stat file failed for jobid %d\n",
+ jobid));
+ goto fail;
+ }
+
+ pjob->status = LPQ_SPOOLING;
+
+ } else {
+
+ if ((sys_fstat(pjob->fd, &sbuf, false) != 0)) {
+ status = map_nt_error_from_unix(errno);
+ close(pjob->fd);
+ DEBUG(3, ("print_job_end: "
+ "stat file failed for jobid %d\n",
+ jobid));
+ goto fail;
+ }
+
+ close(pjob->fd);
+ }
- if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
- (sys_fstat(pjob->fd, &sbuf, false) == 0)) {
pjob->size = sbuf.st_ex_size;
- close(pjob->fd);
- pjob->fd = -1;
} else {
/*
- * Not a normal close or we couldn't stat the job file,
- * so something has gone wrong. Cleanup.
+ * Not a normal close, something has gone wrong. Cleanup.
*/
- close(pjob->fd);
- pjob->fd = -1;
- DEBUG(3,("print_job_end: failed to stat file for jobid %d\n", jobid ));
+ if (pjob->fd != -1) {
+ close(pjob->fd);
+ }
goto fail;
}
pjob->filename, pjob->size ? "deleted" : "zero length" ));
unlink(pjob->filename);
pjob_delete(sharename, jobid);
- return True;
+ return NT_STATUS_OK;
}
ret = (*(current_printif->job_submit))(snum, pjob);
- if (ret)
+ if (ret) {
+ status = NT_STATUS_PRINT_CANCELLED;
goto fail;
+ }
/* The print job has been successfully handed over to the back-end */
if (print_cache_expired(lp_const_servicename(snum), True))
print_queue_update(snum, False);
- return True;
+ return NT_STATUS_OK;
fail:
/* The print job was not successfully started. Cleanup */
/* Still need to add proper error return propagation! 010122:JRR */
+ pjob->fd = -1;
unlink(pjob->filename);
pjob_delete(sharename, jobid);
- return False;
+ return status;
}
/****************************************************************************