»Core Development>Code coverage>PC/_msi.c

Python code coverage for PC/_msi.c

#countcontent
1n/a/* Helper library for MSI creation with Python.
2n/a * Copyright (C) 2005 Martin v. Löwis
3n/a * Licensed to PSF under a contributor agreement.
4n/a */
5n/a
6n/a#include <Python.h>
7n/a#include <fci.h>
8n/a#include <fcntl.h>
9n/a#include <windows.h>
10n/a#include <msi.h>
11n/a#include <msiquery.h>
12n/a#include <msidefs.h>
13n/a#include <rpc.h>
14n/a
15n/astatic PyObject *MSIError;
16n/a
17n/astatic PyObject*
18n/auuidcreate(PyObject* obj, PyObject*args)
19n/a{
20n/a UUID result;
21n/a wchar_t *cresult;
22n/a PyObject *oresult;
23n/a
24n/a /* May return ok, local only, and no address.
25n/a For local only, the documentation says we still get a uuid.
26n/a For RPC_S_UUID_NO_ADDRESS, it's not clear whether we can
27n/a use the result. */
28n/a if (UuidCreate(&result) == RPC_S_UUID_NO_ADDRESS) {
29n/a PyErr_SetString(PyExc_NotImplementedError, "processing 'no address' result");
30n/a return NULL;
31n/a }
32n/a
33n/a if (UuidToStringW(&result, &cresult) == RPC_S_OUT_OF_MEMORY) {
34n/a PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen");
35n/a return NULL;
36n/a }
37n/a
38n/a oresult = PyUnicode_FromWideChar(cresult, wcslen(cresult));
39n/a RpcStringFreeW(&cresult);
40n/a return oresult;
41n/a
42n/a}
43n/a
44n/a/* FCI callback functions */
45n/a
46n/astatic FNFCIALLOC(cb_alloc)
47n/a{
48n/a return malloc(cb);
49n/a}
50n/a
51n/astatic FNFCIFREE(cb_free)
52n/a{
53n/a free(memory);
54n/a}
55n/a
56n/astatic FNFCIOPEN(cb_open)
57n/a{
58n/a int result = _open(pszFile, oflag | O_NOINHERIT, pmode);
59n/a if (result == -1)
60n/a *err = errno;
61n/a return result;
62n/a}
63n/a
64n/astatic FNFCIREAD(cb_read)
65n/a{
66n/a UINT result = (UINT)_read((int)hf, memory, cb);
67n/a if (result != cb)
68n/a *err = errno;
69n/a return result;
70n/a}
71n/a
72n/astatic FNFCIWRITE(cb_write)
73n/a{
74n/a UINT result = (UINT)_write((int)hf, memory, cb);
75n/a if (result != cb)
76n/a *err = errno;
77n/a return result;
78n/a}
79n/a
80n/astatic FNFCICLOSE(cb_close)
81n/a{
82n/a int result = _close((int)hf);
83n/a if (result != 0)
84n/a *err = errno;
85n/a return result;
86n/a}
87n/a
88n/astatic FNFCISEEK(cb_seek)
89n/a{
90n/a long result = (long)_lseek((int)hf, dist, seektype);
91n/a if (result == -1)
92n/a *err = errno;
93n/a return result;
94n/a}
95n/a
96n/astatic FNFCIDELETE(cb_delete)
97n/a{
98n/a int result = remove(pszFile);
99n/a if (result != 0)
100n/a *err = errno;
101n/a return result;
102n/a}
103n/a
104n/astatic FNFCIFILEPLACED(cb_fileplaced)
105n/a{
106n/a return 0;
107n/a}
108n/a
109n/astatic FNFCIGETTEMPFILE(cb_gettempfile)
110n/a{
111n/a char *name = _tempnam("", "tmp");
112n/a if ((name != NULL) && ((int)strlen(name) < cbTempName)) {
113n/a strcpy(pszTempName, name);
114n/a free(name);
115n/a return TRUE;
116n/a }
117n/a
118n/a if (name) free(name);
119n/a return FALSE;
120n/a}
121n/a
122n/astatic FNFCISTATUS(cb_status)
123n/a{
124n/a if (pv) {
125n/a _Py_IDENTIFIER(status);
126n/a
127n/a PyObject *result = _PyObject_CallMethodId(pv, &PyId_status, "iii", typeStatus, cb1, cb2);
128n/a if (result == NULL)
129n/a return -1;
130n/a Py_DECREF(result);
131n/a }
132n/a return 0;
133n/a}
134n/a
135n/astatic FNFCIGETNEXTCABINET(cb_getnextcabinet)
136n/a{
137n/a if (pv) {
138n/a _Py_IDENTIFIER(getnextcabinet);
139n/a
140n/a PyObject *result = _PyObject_CallMethodId(pv, &PyId_getnextcabinet, "i", pccab->iCab);
141n/a if (result == NULL)
142n/a return -1;
143n/a if (!PyBytes_Check(result)) {
144n/a PyErr_Format(PyExc_TypeError,
145n/a "Incorrect return type %s from getnextcabinet",
146n/a result->ob_type->tp_name);
147n/a Py_DECREF(result);
148n/a return FALSE;
149n/a }
150n/a strncpy(pccab->szCab, PyBytes_AsString(result), sizeof(pccab->szCab));
151n/a return TRUE;
152n/a }
153n/a return FALSE;
154n/a}
155n/a
156n/astatic FNFCIGETOPENINFO(cb_getopeninfo)
157n/a{
158n/a BY_HANDLE_FILE_INFORMATION bhfi;
159n/a FILETIME filetime;
160n/a HANDLE handle;
161n/a
162n/a /* Need Win32 handle to get time stamps */
163n/a handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
164n/a OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
165n/a if (handle == INVALID_HANDLE_VALUE)
166n/a return -1;
167n/a
168n/a if (GetFileInformationByHandle(handle, &bhfi) == FALSE)
169n/a {
170n/a CloseHandle(handle);
171n/a return -1;
172n/a }
173n/a
174n/a FileTimeToLocalFileTime(&bhfi.ftLastWriteTime, &filetime);
175n/a FileTimeToDosDateTime(&filetime, pdate, ptime);
176n/a
177n/a *pattribs = (int)(bhfi.dwFileAttributes &
178n/a (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH));
179n/a
180n/a CloseHandle(handle);
181n/a
182n/a return _open(pszName, _O_RDONLY | _O_BINARY | O_NOINHERIT);
183n/a}
184n/a
185n/astatic PyObject* fcicreate(PyObject* obj, PyObject* args)
186n/a{
187n/a char *cabname, *p;
188n/a PyObject *files;
189n/a CCAB ccab;
190n/a HFCI hfci;
191n/a ERF erf;
192n/a Py_ssize_t i;
193n/a
194n/a
195n/a if (!PyArg_ParseTuple(args, "sO:FCICreate", &cabname, &files))
196n/a return NULL;
197n/a
198n/a if (!PyList_Check(files)) {
199n/a PyErr_SetString(PyExc_TypeError, "FCICreate expects a list");
200n/a return NULL;
201n/a }
202n/a
203n/a ccab.cb = INT_MAX; /* no need to split CAB into multiple media */
204n/a ccab.cbFolderThresh = 1000000; /* flush directory after this many bytes */
205n/a ccab.cbReserveCFData = 0;
206n/a ccab.cbReserveCFFolder = 0;
207n/a ccab.cbReserveCFHeader = 0;
208n/a
209n/a ccab.iCab = 1;
210n/a ccab.iDisk = 1;
211n/a
212n/a ccab.setID = 0;
213n/a ccab.szDisk[0] = '\0';
214n/a
215n/a for (i = 0, p = cabname; *p; p = CharNext(p))
216n/a if (*p == '\\' || *p == '/')
217n/a i = p - cabname + 1;
218n/a
219n/a if (i >= sizeof(ccab.szCabPath) ||
220n/a strlen(cabname+i) >= sizeof(ccab.szCab)) {
221n/a PyErr_SetString(PyExc_ValueError, "path name too long");
222n/a return 0;
223n/a }
224n/a
225n/a if (i > 0) {
226n/a memcpy(ccab.szCabPath, cabname, i);
227n/a ccab.szCabPath[i] = '\0';
228n/a strcpy(ccab.szCab, cabname+i);
229n/a } else {
230n/a strcpy(ccab.szCabPath, ".\\");
231n/a strcpy(ccab.szCab, cabname);
232n/a }
233n/a
234n/a hfci = FCICreate(&erf, cb_fileplaced, cb_alloc, cb_free,
235n/a cb_open, cb_read, cb_write, cb_close, cb_seek, cb_delete,
236n/a cb_gettempfile, &ccab, NULL);
237n/a
238n/a if (hfci == NULL) {
239n/a PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper);
240n/a return NULL;
241n/a }
242n/a
243n/a for (i=0; i < PyList_GET_SIZE(files); i++) {
244n/a PyObject *item = PyList_GET_ITEM(files, i);
245n/a char *filename, *cabname;
246n/a
247n/a if (!PyArg_ParseTuple(item, "ss", &filename, &cabname)) {
248n/a PyErr_SetString(PyExc_TypeError, "FCICreate expects a list of tuples containing two strings");
249n/a FCIDestroy(hfci);
250n/a return NULL;
251n/a }
252n/a
253n/a if (!FCIAddFile(hfci, filename, cabname, FALSE,
254n/a cb_getnextcabinet, cb_status, cb_getopeninfo,
255n/a tcompTYPE_MSZIP))
256n/a goto err;
257n/a }
258n/a
259n/a if (!FCIFlushCabinet(hfci, FALSE, cb_getnextcabinet, cb_status))
260n/a goto err;
261n/a
262n/a if (!FCIDestroy(hfci))
263n/a goto err;
264n/a
265n/a Py_RETURN_NONE;
266n/aerr:
267n/a if(erf.fError)
268n/a PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
269n/a else
270n/a PyErr_SetString(PyExc_ValueError, "FCI general error");
271n/a
272n/a FCIDestroy(hfci);
273n/a return NULL;
274n/a}
275n/a
276n/atypedef struct msiobj{
277n/a PyObject_HEAD
278n/a MSIHANDLE h;
279n/a}msiobj;
280n/a
281n/astatic void
282n/amsiobj_dealloc(msiobj* msidb)
283n/a{
284n/a MsiCloseHandle(msidb->h);
285n/a msidb->h = 0;
286n/a}
287n/a
288n/astatic PyObject*
289n/amsiobj_close(msiobj* msidb, PyObject *args)
290n/a{
291n/a MsiCloseHandle(msidb->h);
292n/a msidb->h = 0;
293n/a Py_RETURN_NONE;
294n/a}
295n/a
296n/astatic PyObject*
297n/amsierror(int status)
298n/a{
299n/a int code;
300n/a char buf[2000];
301n/a char *res = buf;
302n/a DWORD size = sizeof(buf);
303n/a MSIHANDLE err = MsiGetLastErrorRecord();
304n/a
305n/a if (err == 0) {
306n/a switch(status) {
307n/a case ERROR_ACCESS_DENIED:
308n/a PyErr_SetString(MSIError, "access denied");
309n/a return NULL;
310n/a case ERROR_FUNCTION_FAILED:
311n/a PyErr_SetString(MSIError, "function failed");
312n/a return NULL;
313n/a case ERROR_INVALID_DATA:
314n/a PyErr_SetString(MSIError, "invalid data");
315n/a return NULL;
316n/a case ERROR_INVALID_HANDLE:
317n/a PyErr_SetString(MSIError, "invalid handle");
318n/a return NULL;
319n/a case ERROR_INVALID_STATE:
320n/a PyErr_SetString(MSIError, "invalid state");
321n/a return NULL;
322n/a case ERROR_INVALID_PARAMETER:
323n/a PyErr_SetString(MSIError, "invalid parameter");
324n/a return NULL;
325n/a default:
326n/a PyErr_Format(MSIError, "unknown error %x", status);
327n/a return NULL;
328n/a }
329n/a }
330n/a
331n/a code = MsiRecordGetInteger(err, 1); /* XXX code */
332n/a if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) {
333n/a res = malloc(size+1);
334n/a MsiFormatRecord(0, err, res, &size);
335n/a res[size]='\0';
336n/a }
337n/a MsiCloseHandle(err);
338n/a PyErr_SetString(MSIError, res);
339n/a if (res != buf)
340n/a free(res);
341n/a return NULL;
342n/a}
343n/a
344n/a/*************************** Record objects **********************/
345n/a
346n/astatic PyObject*
347n/arecord_getfieldcount(msiobj* record, PyObject* args)
348n/a{
349n/a return PyLong_FromLong(MsiRecordGetFieldCount(record->h));
350n/a}
351n/a
352n/astatic PyObject*
353n/arecord_getinteger(msiobj* record, PyObject* args)
354n/a{
355n/a unsigned int field;
356n/a int status;
357n/a
358n/a if (!PyArg_ParseTuple(args, "I:GetInteger", &field))
359n/a return NULL;
360n/a status = MsiRecordGetInteger(record->h, field);
361n/a if (status == MSI_NULL_INTEGER){
362n/a PyErr_SetString(MSIError, "could not convert record field to integer");
363n/a return NULL;
364n/a }
365n/a return PyLong_FromLong((long) status);
366n/a}
367n/a
368n/astatic PyObject*
369n/arecord_getstring(msiobj* record, PyObject* args)
370n/a{
371n/a unsigned int field;
372n/a unsigned int status;
373n/a WCHAR buf[2000];
374n/a WCHAR *res = buf;
375n/a DWORD size = sizeof(buf);
376n/a PyObject* string;
377n/a
378n/a if (!PyArg_ParseTuple(args, "I:GetString", &field))
379n/a return NULL;
380n/a status = MsiRecordGetStringW(record->h, field, res, &size);
381n/a if (status == ERROR_MORE_DATA) {
382n/a res = (WCHAR*) malloc((size + 1)*sizeof(WCHAR));
383n/a if (res == NULL)
384n/a return PyErr_NoMemory();
385n/a status = MsiRecordGetStringW(record->h, field, res, &size);
386n/a }
387n/a if (status != ERROR_SUCCESS)
388n/a return msierror((int) status);
389n/a string = PyUnicode_FromWideChar(res, size);
390n/a if (buf != res)
391n/a free(res);
392n/a return string;
393n/a}
394n/a
395n/astatic PyObject*
396n/arecord_cleardata(msiobj* record, PyObject *args)
397n/a{
398n/a int status = MsiRecordClearData(record->h);
399n/a if (status != ERROR_SUCCESS)
400n/a return msierror(status);
401n/a
402n/a Py_RETURN_NONE;
403n/a}
404n/a
405n/astatic PyObject*
406n/arecord_setstring(msiobj* record, PyObject *args)
407n/a{
408n/a int status;
409n/a int field;
410n/a wchar_t *data;
411n/a
412n/a if (!PyArg_ParseTuple(args, "iu:SetString", &field, &data))
413n/a return NULL;
414n/a
415n/a if ((status = MsiRecordSetStringW(record->h, field, data)) != ERROR_SUCCESS)
416n/a return msierror(status);
417n/a
418n/a Py_RETURN_NONE;
419n/a}
420n/a
421n/astatic PyObject*
422n/arecord_setstream(msiobj* record, PyObject *args)
423n/a{
424n/a int status;
425n/a int field;
426n/a wchar_t *data;
427n/a
428n/a if (!PyArg_ParseTuple(args, "iu:SetStream", &field, &data))
429n/a return NULL;
430n/a
431n/a if ((status = MsiRecordSetStreamW(record->h, field, data)) != ERROR_SUCCESS)
432n/a return msierror(status);
433n/a
434n/a Py_RETURN_NONE;
435n/a}
436n/a
437n/astatic PyObject*
438n/arecord_setinteger(msiobj* record, PyObject *args)
439n/a{
440n/a int status;
441n/a int field;
442n/a int data;
443n/a
444n/a if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data))
445n/a return NULL;
446n/a
447n/a if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS)
448n/a return msierror(status);
449n/a
450n/a Py_RETURN_NONE;
451n/a}
452n/a
453n/a
454n/a
455n/astatic PyMethodDef record_methods[] = {
456n/a { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS,
457n/a PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")},
458n/a { "GetInteger", (PyCFunction)record_getinteger, METH_VARARGS,
459n/a PyDoc_STR("GetInteger(field) -> int\nWraps MsiRecordGetInteger")},
460n/a { "GetString", (PyCFunction)record_getstring, METH_VARARGS,
461n/a PyDoc_STR("GetString(field) -> string\nWraps MsiRecordGetString")},
462n/a { "SetString", (PyCFunction)record_setstring, METH_VARARGS,
463n/a PyDoc_STR("SetString(field,str) -> None\nWraps MsiRecordSetString")},
464n/a { "SetStream", (PyCFunction)record_setstream, METH_VARARGS,
465n/a PyDoc_STR("SetStream(field,filename) -> None\nWraps MsiRecordSetInteger")},
466n/a { "SetInteger", (PyCFunction)record_setinteger, METH_VARARGS,
467n/a PyDoc_STR("SetInteger(field,int) -> None\nWraps MsiRecordSetInteger")},
468n/a { "ClearData", (PyCFunction)record_cleardata, METH_NOARGS,
469n/a PyDoc_STR("ClearData() -> int\nWraps MsiRecordGClearData")},
470n/a { NULL, NULL }
471n/a};
472n/a
473n/astatic PyTypeObject record_Type = {
474n/a PyVarObject_HEAD_INIT(NULL, 0)
475n/a "_msi.Record", /*tp_name*/
476n/a sizeof(msiobj), /*tp_basicsize*/
477n/a 0, /*tp_itemsize*/
478n/a /* methods */
479n/a (destructor)msiobj_dealloc, /*tp_dealloc*/
480n/a 0, /*tp_print*/
481n/a 0, /*tp_getattr*/
482n/a 0, /*tp_setattr*/
483n/a 0, /*tp_reserved*/
484n/a 0, /*tp_repr*/
485n/a 0, /*tp_as_number*/
486n/a 0, /*tp_as_sequence*/
487n/a 0, /*tp_as_mapping*/
488n/a 0, /*tp_hash*/
489n/a 0, /*tp_call*/
490n/a 0, /*tp_str*/
491n/a PyObject_GenericGetAttr,/*tp_getattro*/
492n/a PyObject_GenericSetAttr,/*tp_setattro*/
493n/a 0, /*tp_as_buffer*/
494n/a Py_TPFLAGS_DEFAULT, /*tp_flags*/
495n/a 0, /*tp_doc*/
496n/a 0, /*tp_traverse*/
497n/a 0, /*tp_clear*/
498n/a 0, /*tp_richcompare*/
499n/a 0, /*tp_weaklistoffset*/
500n/a 0, /*tp_iter*/
501n/a 0, /*tp_iternext*/
502n/a record_methods, /*tp_methods*/
503n/a 0, /*tp_members*/
504n/a 0, /*tp_getset*/
505n/a 0, /*tp_base*/
506n/a 0, /*tp_dict*/
507n/a 0, /*tp_descr_get*/
508n/a 0, /*tp_descr_set*/
509n/a 0, /*tp_dictoffset*/
510n/a 0, /*tp_init*/
511n/a 0, /*tp_alloc*/
512n/a 0, /*tp_new*/
513n/a 0, /*tp_free*/
514n/a 0, /*tp_is_gc*/
515n/a};
516n/a
517n/astatic PyObject*
518n/arecord_new(MSIHANDLE h)
519n/a{
520n/a msiobj *result = PyObject_NEW(struct msiobj, &record_Type);
521n/a
522n/a if (!result) {
523n/a MsiCloseHandle(h);
524n/a return NULL;
525n/a }
526n/a
527n/a result->h = h;
528n/a return (PyObject*)result;
529n/a}
530n/a
531n/a/*************************** SummaryInformation objects **************/
532n/a
533n/astatic PyObject*
534n/asummary_getproperty(msiobj* si, PyObject *args)
535n/a{
536n/a int status;
537n/a int field;
538n/a PyObject *result;
539n/a UINT type;
540n/a INT ival;
541n/a FILETIME fval;
542n/a char sbuf[1000];
543n/a char *sval = sbuf;
544n/a DWORD ssize = sizeof(sval);
545n/a
546n/a if (!PyArg_ParseTuple(args, "i:GetProperty", &field))
547n/a return NULL;
548n/a
549n/a status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
550n/a &fval, sval, &ssize);
551n/a if (status == ERROR_MORE_DATA) {
552n/a sval = malloc(ssize);
553n/a status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
554n/a &fval, sval, &ssize);
555n/a }
556n/a
557n/a switch(type) {
558n/a case VT_I2: case VT_I4:
559n/a return PyLong_FromLong(ival);
560n/a case VT_FILETIME:
561n/a PyErr_SetString(PyExc_NotImplementedError, "FILETIME result");
562n/a return NULL;
563n/a case VT_LPSTR:
564n/a result = PyBytes_FromStringAndSize(sval, ssize);
565n/a if (sval != sbuf)
566n/a free(sval);
567n/a return result;
568n/a }
569n/a PyErr_Format(PyExc_NotImplementedError, "result of type %d", type);
570n/a return NULL;
571n/a}
572n/a
573n/astatic PyObject*
574n/asummary_getpropertycount(msiobj* si, PyObject *args)
575n/a{
576n/a int status;
577n/a UINT result;
578n/a
579n/a status = MsiSummaryInfoGetPropertyCount(si->h, &result);
580n/a if (status != ERROR_SUCCESS)
581n/a return msierror(status);
582n/a
583n/a return PyLong_FromLong(result);
584n/a}
585n/a
586n/astatic PyObject*
587n/asummary_setproperty(msiobj* si, PyObject *args)
588n/a{
589n/a int status;
590n/a int field;
591n/a PyObject* data;
592n/a
593n/a if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data))
594n/a return NULL;
595n/a
596n/a if (PyUnicode_Check(data)) {
597n/a status = MsiSummaryInfoSetPropertyW(si->h, field, VT_LPSTR,
598n/a 0, NULL, PyUnicode_AsUnicode(data));
599n/a } else if (PyLong_CheckExact(data)) {
600n/a long value = PyLong_AsLong(data);
601n/a if (value == -1 && PyErr_Occurred()) {
602n/a return NULL;
603n/a }
604n/a status = MsiSummaryInfoSetProperty(si->h, field, VT_I4,
605n/a value, NULL, NULL);
606n/a } else {
607n/a PyErr_SetString(PyExc_TypeError, "unsupported type");
608n/a return NULL;
609n/a }
610n/a
611n/a if (status != ERROR_SUCCESS)
612n/a return msierror(status);
613n/a
614n/a Py_RETURN_NONE;
615n/a}
616n/a
617n/a
618n/astatic PyObject*
619n/asummary_persist(msiobj* si, PyObject *args)
620n/a{
621n/a int status;
622n/a
623n/a status = MsiSummaryInfoPersist(si->h);
624n/a if (status != ERROR_SUCCESS)
625n/a return msierror(status);
626n/a Py_RETURN_NONE;
627n/a}
628n/a
629n/astatic PyMethodDef summary_methods[] = {
630n/a { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS,
631n/a PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")},
632n/a { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS,
633n/a PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")},
634n/a { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS,
635n/a PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")},
636n/a { "Persist", (PyCFunction)summary_persist, METH_NOARGS,
637n/a PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")},
638n/a { NULL, NULL }
639n/a};
640n/a
641n/astatic PyTypeObject summary_Type = {
642n/a PyVarObject_HEAD_INIT(NULL, 0)
643n/a "_msi.SummaryInformation", /*tp_name*/
644n/a sizeof(msiobj), /*tp_basicsize*/
645n/a 0, /*tp_itemsize*/
646n/a /* methods */
647n/a (destructor)msiobj_dealloc, /*tp_dealloc*/
648n/a 0, /*tp_print*/
649n/a 0, /*tp_getattr*/
650n/a 0, /*tp_setattr*/
651n/a 0, /*tp_reserved*/
652n/a 0, /*tp_repr*/
653n/a 0, /*tp_as_number*/
654n/a 0, /*tp_as_sequence*/
655n/a 0, /*tp_as_mapping*/
656n/a 0, /*tp_hash*/
657n/a 0, /*tp_call*/
658n/a 0, /*tp_str*/
659n/a PyObject_GenericGetAttr,/*tp_getattro*/
660n/a PyObject_GenericSetAttr,/*tp_setattro*/
661n/a 0, /*tp_as_buffer*/
662n/a Py_TPFLAGS_DEFAULT, /*tp_flags*/
663n/a 0, /*tp_doc*/
664n/a 0, /*tp_traverse*/
665n/a 0, /*tp_clear*/
666n/a 0, /*tp_richcompare*/
667n/a 0, /*tp_weaklistoffset*/
668n/a 0, /*tp_iter*/
669n/a 0, /*tp_iternext*/
670n/a summary_methods, /*tp_methods*/
671n/a 0, /*tp_members*/
672n/a 0, /*tp_getset*/
673n/a 0, /*tp_base*/
674n/a 0, /*tp_dict*/
675n/a 0, /*tp_descr_get*/
676n/a 0, /*tp_descr_set*/
677n/a 0, /*tp_dictoffset*/
678n/a 0, /*tp_init*/
679n/a 0, /*tp_alloc*/
680n/a 0, /*tp_new*/
681n/a 0, /*tp_free*/
682n/a 0, /*tp_is_gc*/
683n/a};
684n/a
685n/a/*************************** View objects **************/
686n/a
687n/astatic PyObject*
688n/aview_execute(msiobj *view, PyObject*args)
689n/a{
690n/a int status;
691n/a MSIHANDLE params = 0;
692n/a PyObject *oparams = Py_None;
693n/a
694n/a if (!PyArg_ParseTuple(args, "O:Execute", &oparams))
695n/a return NULL;
696n/a
697n/a if (oparams != Py_None) {
698n/a if (oparams->ob_type != &record_Type) {
699n/a PyErr_SetString(PyExc_TypeError, "Execute argument must be a record");
700n/a return NULL;
701n/a }
702n/a params = ((msiobj*)oparams)->h;
703n/a }
704n/a
705n/a status = MsiViewExecute(view->h, params);
706n/a if (status != ERROR_SUCCESS)
707n/a return msierror(status);
708n/a
709n/a Py_RETURN_NONE;
710n/a}
711n/a
712n/astatic PyObject*
713n/aview_fetch(msiobj *view, PyObject*args)
714n/a{
715n/a int status;
716n/a MSIHANDLE result;
717n/a
718n/a if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS)
719n/a return msierror(status);
720n/a
721n/a return record_new(result);
722n/a}
723n/a
724n/astatic PyObject*
725n/aview_getcolumninfo(msiobj *view, PyObject *args)
726n/a{
727n/a int status;
728n/a int kind;
729n/a MSIHANDLE result;
730n/a
731n/a if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind))
732n/a return NULL;
733n/a
734n/a if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS)
735n/a return msierror(status);
736n/a
737n/a return record_new(result);
738n/a}
739n/a
740n/astatic PyObject*
741n/aview_modify(msiobj *view, PyObject *args)
742n/a{
743n/a int kind;
744n/a PyObject *data;
745n/a int status;
746n/a
747n/a if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data))
748n/a return NULL;
749n/a
750n/a if (data->ob_type != &record_Type) {
751n/a PyErr_SetString(PyExc_TypeError, "Modify expects a record object");
752n/a return NULL;
753n/a }
754n/a
755n/a if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS)
756n/a return msierror(status);
757n/a
758n/a Py_RETURN_NONE;
759n/a}
760n/a
761n/astatic PyObject*
762n/aview_close(msiobj *view, PyObject*args)
763n/a{
764n/a int status;
765n/a
766n/a if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS)
767n/a return msierror(status);
768n/a
769n/a Py_RETURN_NONE;
770n/a}
771n/a
772n/astatic PyMethodDef view_methods[] = {
773n/a { "Execute", (PyCFunction)view_execute, METH_VARARGS,
774n/a PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")},
775n/a { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS,
776n/a PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")},
777n/a { "Fetch", (PyCFunction)view_fetch, METH_NOARGS,
778n/a PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")},
779n/a { "Modify", (PyCFunction)view_modify, METH_VARARGS,
780n/a PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")},
781n/a { "Close", (PyCFunction)view_close, METH_NOARGS,
782n/a PyDoc_STR("Close() -> result\nWraps MsiViewClose")},
783n/a { NULL, NULL }
784n/a};
785n/a
786n/astatic PyTypeObject msiview_Type = {
787n/a PyVarObject_HEAD_INIT(NULL, 0)
788n/a "_msi.View", /*tp_name*/
789n/a sizeof(msiobj), /*tp_basicsize*/
790n/a 0, /*tp_itemsize*/
791n/a /* methods */
792n/a (destructor)msiobj_dealloc, /*tp_dealloc*/
793n/a 0, /*tp_print*/
794n/a 0, /*tp_getattr*/
795n/a 0, /*tp_setattr*/
796n/a 0, /*tp_reserved*/
797n/a 0, /*tp_repr*/
798n/a 0, /*tp_as_number*/
799n/a 0, /*tp_as_sequence*/
800n/a 0, /*tp_as_mapping*/
801n/a 0, /*tp_hash*/
802n/a 0, /*tp_call*/
803n/a 0, /*tp_str*/
804n/a PyObject_GenericGetAttr,/*tp_getattro*/
805n/a PyObject_GenericSetAttr,/*tp_setattro*/
806n/a 0, /*tp_as_buffer*/
807n/a Py_TPFLAGS_DEFAULT, /*tp_flags*/
808n/a 0, /*tp_doc*/
809n/a 0, /*tp_traverse*/
810n/a 0, /*tp_clear*/
811n/a 0, /*tp_richcompare*/
812n/a 0, /*tp_weaklistoffset*/
813n/a 0, /*tp_iter*/
814n/a 0, /*tp_iternext*/
815n/a view_methods, /*tp_methods*/
816n/a 0, /*tp_members*/
817n/a 0, /*tp_getset*/
818n/a 0, /*tp_base*/
819n/a 0, /*tp_dict*/
820n/a 0, /*tp_descr_get*/
821n/a 0, /*tp_descr_set*/
822n/a 0, /*tp_dictoffset*/
823n/a 0, /*tp_init*/
824n/a 0, /*tp_alloc*/
825n/a 0, /*tp_new*/
826n/a 0, /*tp_free*/
827n/a 0, /*tp_is_gc*/
828n/a};
829n/a
830n/a/*************************** Database objects **************/
831n/a
832n/astatic PyObject*
833n/amsidb_openview(msiobj *msidb, PyObject *args)
834n/a{
835n/a int status;
836n/a char *sql;
837n/a MSIHANDLE hView;
838n/a msiobj *result;
839n/a
840n/a if (!PyArg_ParseTuple(args, "s:OpenView", &sql))
841n/a return NULL;
842n/a
843n/a if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS)
844n/a return msierror(status);
845n/a
846n/a result = PyObject_NEW(struct msiobj, &msiview_Type);
847n/a if (!result) {
848n/a MsiCloseHandle(hView);
849n/a return NULL;
850n/a }
851n/a
852n/a result->h = hView;
853n/a return (PyObject*)result;
854n/a}
855n/a
856n/astatic PyObject*
857n/amsidb_commit(msiobj *msidb, PyObject *args)
858n/a{
859n/a int status;
860n/a
861n/a if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS)
862n/a return msierror(status);
863n/a
864n/a Py_RETURN_NONE;
865n/a}
866n/a
867n/astatic PyObject*
868n/amsidb_getsummaryinformation(msiobj *db, PyObject *args)
869n/a{
870n/a int status;
871n/a int count;
872n/a MSIHANDLE result;
873n/a msiobj *oresult;
874n/a
875n/a if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count))
876n/a return NULL;
877n/a
878n/a status = MsiGetSummaryInformation(db->h, NULL, count, &result);
879n/a if (status != ERROR_SUCCESS)
880n/a return msierror(status);
881n/a
882n/a oresult = PyObject_NEW(struct msiobj, &summary_Type);
883n/a if (!result) {
884n/a MsiCloseHandle(result);
885n/a return NULL;
886n/a }
887n/a
888n/a oresult->h = result;
889n/a return (PyObject*)oresult;
890n/a}
891n/a
892n/astatic PyMethodDef db_methods[] = {
893n/a { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS,
894n/a PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")},
895n/a { "Commit", (PyCFunction)msidb_commit, METH_NOARGS,
896n/a PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")},
897n/a { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS,
898n/a PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")},
899n/a { NULL, NULL }
900n/a};
901n/a
902n/astatic PyTypeObject msidb_Type = {
903n/a PyVarObject_HEAD_INIT(NULL, 0)
904n/a "_msi.Database", /*tp_name*/
905n/a sizeof(msiobj), /*tp_basicsize*/
906n/a 0, /*tp_itemsize*/
907n/a /* methods */
908n/a (destructor)msiobj_dealloc, /*tp_dealloc*/
909n/a 0, /*tp_print*/
910n/a 0, /*tp_getattr*/
911n/a 0, /*tp_setattr*/
912n/a 0, /*tp_reserved*/
913n/a 0, /*tp_repr*/
914n/a 0, /*tp_as_number*/
915n/a 0, /*tp_as_sequence*/
916n/a 0, /*tp_as_mapping*/
917n/a 0, /*tp_hash*/
918n/a 0, /*tp_call*/
919n/a 0, /*tp_str*/
920n/a PyObject_GenericGetAttr,/*tp_getattro*/
921n/a PyObject_GenericSetAttr,/*tp_setattro*/
922n/a 0, /*tp_as_buffer*/
923n/a Py_TPFLAGS_DEFAULT, /*tp_flags*/
924n/a 0, /*tp_doc*/
925n/a 0, /*tp_traverse*/
926n/a 0, /*tp_clear*/
927n/a 0, /*tp_richcompare*/
928n/a 0, /*tp_weaklistoffset*/
929n/a 0, /*tp_iter*/
930n/a 0, /*tp_iternext*/
931n/a db_methods, /*tp_methods*/
932n/a 0, /*tp_members*/
933n/a 0, /*tp_getset*/
934n/a 0, /*tp_base*/
935n/a 0, /*tp_dict*/
936n/a 0, /*tp_descr_get*/
937n/a 0, /*tp_descr_set*/
938n/a 0, /*tp_dictoffset*/
939n/a 0, /*tp_init*/
940n/a 0, /*tp_alloc*/
941n/a 0, /*tp_new*/
942n/a 0, /*tp_free*/
943n/a 0, /*tp_is_gc*/
944n/a};
945n/a
946n/a#define Py_NOT_PERSIST(x, flag) \
947n/a (x != (int)(flag) && \
948n/a x != ((int)(flag) | MSIDBOPEN_PATCHFILE))
949n/a
950n/a#define Py_INVALID_PERSIST(x) \
951n/a (Py_NOT_PERSIST(x, MSIDBOPEN_READONLY) && \
952n/a Py_NOT_PERSIST(x, MSIDBOPEN_TRANSACT) && \
953n/a Py_NOT_PERSIST(x, MSIDBOPEN_DIRECT) && \
954n/a Py_NOT_PERSIST(x, MSIDBOPEN_CREATE) && \
955n/a Py_NOT_PERSIST(x, MSIDBOPEN_CREATEDIRECT))
956n/a
957n/astatic PyObject* msiopendb(PyObject *obj, PyObject *args)
958n/a{
959n/a int status;
960n/a char *path;
961n/a int persist;
962n/a MSIHANDLE h;
963n/a msiobj *result;
964n/a if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist))
965n/a return NULL;
966n/a /* We need to validate that persist is a valid MSIDBOPEN_* value. Otherwise,
967n/a MsiOpenDatabase may treat the value as a pointer, leading to unexpected
968n/a behavior. */
969n/a if (Py_INVALID_PERSIST(persist))
970n/a return msierror(ERROR_INVALID_PARAMETER);
971n/a status = MsiOpenDatabase(path, (LPCSTR)persist, &h);
972n/a if (status != ERROR_SUCCESS)
973n/a return msierror(status);
974n/a
975n/a result = PyObject_NEW(struct msiobj, &msidb_Type);
976n/a if (!result) {
977n/a MsiCloseHandle(h);
978n/a return NULL;
979n/a }
980n/a result->h = h;
981n/a return (PyObject*)result;
982n/a}
983n/a
984n/astatic PyObject*
985n/acreaterecord(PyObject *o, PyObject *args)
986n/a{
987n/a int count;
988n/a MSIHANDLE h;
989n/a
990n/a if (!PyArg_ParseTuple(args, "i:CreateRecord", &count))
991n/a return NULL;
992n/a
993n/a h = MsiCreateRecord(count);
994n/a if (h == 0)
995n/a return msierror(0);
996n/a
997n/a return record_new(h);
998n/a}
999n/a
1000n/a
1001n/astatic PyMethodDef msi_methods[] = {
1002n/a {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS,
1003n/a PyDoc_STR("UuidCreate() -> string")},
1004n/a {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS,
1005n/a PyDoc_STR("fcicreate(cabname,files) -> None")},
1006n/a {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS,
1007n/a PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")},
1008n/a {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS,
1009n/a PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")},
1010n/a {NULL, NULL} /* sentinel */
1011n/a};
1012n/a
1013n/astatic char msi_doc[] = "Documentation";
1014n/a
1015n/a
1016n/astatic struct PyModuleDef _msimodule = {
1017n/a PyModuleDef_HEAD_INIT,
1018n/a "_msi",
1019n/a msi_doc,
1020n/a -1,
1021n/a msi_methods,
1022n/a NULL,
1023n/a NULL,
1024n/a NULL,
1025n/a NULL
1026n/a};
1027n/a
1028n/aPyMODINIT_FUNC
1029n/aPyInit__msi(void)
1030n/a{
1031n/a PyObject *m;
1032n/a
1033n/a m = PyModule_Create(&_msimodule);
1034n/a if (m == NULL)
1035n/a return NULL;
1036n/a
1037n/a PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (long)MSIDBOPEN_CREATEDIRECT);
1038n/a PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (long)MSIDBOPEN_CREATE);
1039n/a PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (long)MSIDBOPEN_DIRECT);
1040n/a PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (long)MSIDBOPEN_READONLY);
1041n/a PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (long)MSIDBOPEN_TRANSACT);
1042n/a PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (long)MSIDBOPEN_PATCHFILE);
1043n/a
1044n/a PyModule_AddIntMacro(m, MSICOLINFO_NAMES);
1045n/a PyModule_AddIntMacro(m, MSICOLINFO_TYPES);
1046n/a
1047n/a PyModule_AddIntMacro(m, MSIMODIFY_SEEK);
1048n/a PyModule_AddIntMacro(m, MSIMODIFY_REFRESH);
1049n/a PyModule_AddIntMacro(m, MSIMODIFY_INSERT);
1050n/a PyModule_AddIntMacro(m, MSIMODIFY_UPDATE);
1051n/a PyModule_AddIntMacro(m, MSIMODIFY_ASSIGN);
1052n/a PyModule_AddIntMacro(m, MSIMODIFY_REPLACE);
1053n/a PyModule_AddIntMacro(m, MSIMODIFY_MERGE);
1054n/a PyModule_AddIntMacro(m, MSIMODIFY_DELETE);
1055n/a PyModule_AddIntMacro(m, MSIMODIFY_INSERT_TEMPORARY);
1056n/a PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE);
1057n/a PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_NEW);
1058n/a PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_FIELD);
1059n/a PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_DELETE);
1060n/a
1061n/a PyModule_AddIntMacro(m, PID_CODEPAGE);
1062n/a PyModule_AddIntMacro(m, PID_TITLE);
1063n/a PyModule_AddIntMacro(m, PID_SUBJECT);
1064n/a PyModule_AddIntMacro(m, PID_AUTHOR);
1065n/a PyModule_AddIntMacro(m, PID_KEYWORDS);
1066n/a PyModule_AddIntMacro(m, PID_COMMENTS);
1067n/a PyModule_AddIntMacro(m, PID_TEMPLATE);
1068n/a PyModule_AddIntMacro(m, PID_LASTAUTHOR);
1069n/a PyModule_AddIntMacro(m, PID_REVNUMBER);
1070n/a PyModule_AddIntMacro(m, PID_LASTPRINTED);
1071n/a PyModule_AddIntMacro(m, PID_CREATE_DTM);
1072n/a PyModule_AddIntMacro(m, PID_LASTSAVE_DTM);
1073n/a PyModule_AddIntMacro(m, PID_PAGECOUNT);
1074n/a PyModule_AddIntMacro(m, PID_WORDCOUNT);
1075n/a PyModule_AddIntMacro(m, PID_CHARCOUNT);
1076n/a PyModule_AddIntMacro(m, PID_APPNAME);
1077n/a PyModule_AddIntMacro(m, PID_SECURITY);
1078n/a
1079n/a MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL);
1080n/a if (!MSIError)
1081n/a return NULL;
1082n/a PyModule_AddObject(m, "MSIError", MSIError);
1083n/a return m;
1084n/a}