7cce869c28f8d0c73d8cc5bcdb325b17f7a1f574
[reactos.git] / reactos / win32ss / printing / providers / localspl / jobs.c
1 /*
2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Functions for managing print jobs
5 * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 LIST_ENTRY LocalJobQueue;
11
12 void
13 InitializeJobQueue()
14 {
15 const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
16 const DWORD cchPath = _countof(wszPath) - 1;
17 const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1;
18 const DWORD cchPattern = sizeof("?????") - 1;
19
20 DWORD dwJobID;
21 HANDLE hFind;
22 PLOCAL_JOB pJob;
23 PWSTR p;
24 WCHAR wszFullPath[MAX_PATH];
25 WIN32_FIND_DATAW FindData;
26
27 // Construct the full path search pattern.
28 CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
29 CopyMemory(&wszFullPath[cchSpoolDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR));
30
31 // Use the search pattern to look for unfinished jobs serialized in shadow files (.SHD)
32 hFind = FindFirstFileW(wszFullPath, &FindData);
33 if (hFind == INVALID_HANDLE_VALUE)
34 {
35 // No unfinished jobs found.
36 return;
37 }
38
39 do
40 {
41 // Skip possible subdirectories.
42 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
43 continue;
44
45 // Extract the Job ID and verify the file name format at the same time.
46 dwJobID = wcstoul(FindData.cFileName, &p, 10);
47 if (!IS_VALID_JOB_ID(dwJobID))
48 continue;
49
50 if (wcsicmp(p, L".SHD") != 0)
51 continue;
52
53 // This shadow file has a valid name. Construct the full path and try to load it.
54 CopyMemory(&wszFullPath[cchSpoolDirectory + cchFolders], FindData.cFileName, cchPattern);
55 pJob = ReadJobShadowFile(wszFullPath);
56 if (!pJob)
57 continue;
58
59 // Add it to the job queue of the respective printer.
60 InsertTailList(&pJob->Printer->JobQueue, &pJob->Entry);
61 }
62 while (FindNextFileW(hFind, &FindData));
63
64 FindClose(hFind);
65 }
66
67 PLOCAL_JOB
68 ReadJobShadowFile(PCWSTR pwszFilePath)
69 {
70 DWORD cbFileSize;
71 DWORD cbRead;
72 HANDLE hFile = INVALID_HANDLE_VALUE;
73 PLOCAL_JOB pJob;
74 PLOCAL_JOB pReturnValue = NULL;
75 PLOCAL_PRINTER pPrinter;
76 PSHD_HEADER pShadowFile = NULL;
77 PWSTR pwszPrinterName;
78
79 // Try to open the file.
80 hFile = CreateFileW(pwszFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
81 if (hFile == INVALID_HANDLE_VALUE)
82 {
83 ERR("CreateFileW failed with error %lu!\n", GetLastError());
84 goto Cleanup;
85 }
86
87 // Get its file size (small enough for a single DWORD) and allocate memory for all of it.
88 cbFileSize = GetFileSize(hFile, NULL);
89 pShadowFile = DllAllocSplMem(cbFileSize);
90 if (!pShadowFile)
91 {
92 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
93 goto Cleanup;
94 }
95
96 // Read the entire file.
97 if (!ReadFile(hFile, pShadowFile, cbFileSize, &cbRead, NULL))
98 {
99 ERR("ReadFile failed with error %lu!\n", GetLastError());
100 goto Cleanup;
101 }
102
103 // Check signature and header size.
104 if (pShadowFile->dwSignature != SHD_WIN2003_SIGNATURE || pShadowFile->cbHeader != sizeof(SHD_HEADER))
105 {
106 ERR("Signature or Header Size mismatch!\n");
107 goto Cleanup;
108 }
109
110 // Retrieve the associated printer from the table.
111 pwszPrinterName = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrinterName);
112 pPrinter = RtlLookupElementGenericTable(&PrinterTable, pwszPrinterName);
113 if (!pPrinter)
114 {
115 ERR("This shadow file references a non-existing printer!\n");
116 goto Cleanup;
117 }
118
119 // Create a new job structure and copy over the relevant fields.
120 pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
121 if (!pJob)
122 {
123 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
124 goto Cleanup;
125 }
126
127 pJob->dwJobID = pShadowFile->dwJobID;
128 pJob->Printer = pPrinter;
129 pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype));
130 pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName));
131 pJob->pwszOutputFile = NULL;
132 CopyMemory(&pJob->DevMode, (PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode), sizeof(DEVMODEW));
133
134 pReturnValue = pJob;
135
136 Cleanup:
137 if (pShadowFile)
138 DllFreeSplMem(pShadowFile);
139
140 if (hFile != INVALID_HANDLE_VALUE)
141 CloseHandle(hFile);
142
143 return pReturnValue;
144 }
145
146 BOOL
147 WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob)
148 {
149 BOOL bReturnValue = FALSE;
150 DWORD cbDatatype;
151 DWORD cbDocumentName;
152 DWORD cbFileSize;
153 DWORD cbPrinterName;
154 DWORD cbWritten;
155 DWORD dwCurrentOffset;
156 HANDLE hFile = INVALID_HANDLE_VALUE;
157 PSHD_HEADER pShadowFile = NULL;
158
159 // Try to open the file.
160 hFile = CreateFileW(pwszFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
161 if (hFile == INVALID_HANDLE_VALUE)
162 {
163 ERR("CreateFileW failed with error %lu!\n", GetLastError());
164 goto Cleanup;
165 }
166
167 // Compute the total size of the shadow file.
168 cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
169 cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
170 cbPrinterName = (wcslen(pJob->Printer->pwszPrinterName) + 1) * sizeof(WCHAR);
171 cbFileSize = sizeof(SHD_HEADER) + cbDatatype + cbDocumentName + cbPrinterName;
172
173 // Allocate memory for it.
174 pShadowFile = DllAllocSplMem(cbFileSize);
175 if (!pShadowFile)
176 {
177 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
178 goto Cleanup;
179 }
180
181 // Fill out the shadow file header information.
182 pShadowFile->dwSignature = SHD_WIN2003_SIGNATURE;
183 pShadowFile->cbHeader = sizeof(SHD_HEADER);
184 pShadowFile->dwJobID = pJob->dwJobID;
185
186 // Add the extra values that are stored as offsets in the shadow file.
187 // The first value begins right after the shadow file header.
188 dwCurrentOffset = sizeof(SHD_HEADER);
189
190 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDatatype, cbDatatype);
191 pShadowFile->offDatatype = dwCurrentOffset;
192 dwCurrentOffset += cbDatatype;
193
194 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDocumentName, cbDocumentName);
195 pShadowFile->offDocumentName = dwCurrentOffset;
196 dwCurrentOffset += cbDocumentName;
197
198 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->Printer->pwszPrinterName, cbPrinterName);
199 pShadowFile->offPrinterName = dwCurrentOffset;
200 dwCurrentOffset += cbPrinterName;
201
202 // Write the file.
203 if (!WriteFile(hFile, pShadowFile, cbFileSize, &cbWritten, NULL))
204 {
205 ERR("WriteFile failed with error %lu!\n", GetLastError());
206 goto Cleanup;
207 }
208
209 bReturnValue = TRUE;
210
211 Cleanup:
212 if (pShadowFile)
213 DllFreeSplMem(pShadowFile);
214
215 if (hFile != INVALID_HANDLE_VALUE)
216 CloseHandle(hFile);
217
218 return bReturnValue;
219 }
220
221 BOOL
222 FreeJob(PLOCAL_JOB pJob)
223 {
224 ////////// TODO /////////
225 /// Add some checks
226 DllFreeSplStr(pJob->pwszDatatype);
227 DllFreeSplStr(pJob->pwszDocumentName);
228 DllFreeSplStr(pJob->pwszOutputFile);
229 DllFreeSplMem(pJob);
230
231 return TRUE;
232 }