Use RAII for get_storage_info()

This commit is contained in:
Kovid Goyal 2021-04-20 22:37:43 +05:30
parent 014f7fe82a
commit d7150a4b86
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 80 additions and 94 deletions

View File

@ -45,13 +45,13 @@ IPortableDeviceValues *get_client_information() { // {{{
return client_information.Detach();
} // }}}
IPortableDevice *open_device(const wchar_t *pnp_id, CComPtr<IPortableDeviceValues> &client_information) { // {{{
IPortableDevice *device = NULL;
IPortableDevice*
open_device(const wchar_t *pnp_id, CComPtr<IPortableDeviceValues> &client_information) { // {{{
CComPtr<IPortableDevice> device;
HRESULT hr;
Py_BEGIN_ALLOW_THREADS;
hr = CoCreateInstance(CLSID_PortableDevice, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&device));
hr = device.CoCreateInstance(CLSID_PortableDevice, NULL, CLSCTX_INPROC_SERVER);
Py_END_ALLOW_THREADS;
if (FAILED(hr)) { hresult_set_exc("Failed to create IPortableDevice", hr); device = NULL; }
else {
@ -60,82 +60,80 @@ IPortableDevice *open_device(const wchar_t *pnp_id, CComPtr<IPortableDeviceValue
Py_END_ALLOW_THREADS;
if FAILED(hr) {
Py_BEGIN_ALLOW_THREADS;
device->Release();
device.Release();
Py_END_ALLOW_THREADS;
device = NULL;
hresult_set_exc((hr == E_ACCESSDENIED) ? "Read/write access to device is denied": "Failed to open device", hr);
}
}
return device;
return device.Detach();
} // }}}
PyObject* get_storage_info(IPortableDevice *device) { // {{{
static PyObject*
get_storage_info(IPortableDevice *device) { // {{{
HRESULT hr, hr2;
IPortableDeviceContent *content = NULL;
IEnumPortableDeviceObjectIDs *objects = NULL;
IPortableDeviceProperties *properties = NULL;
IPortableDeviceKeyCollection *storage_properties = NULL;
IPortableDeviceValues *values = NULL;
PyObject *ans = NULL, *storage = NULL, *so = NULL, *desc = NULL, *soid = NULL;
CComPtr<IPortableDeviceContent> content = NULL;
CComPtr<IEnumPortableDeviceObjectIDs> objects = NULL;
CComPtr<IPortableDeviceProperties> properties = NULL;
CComPtr<IPortableDeviceKeyCollection> storage_properties = NULL;
DWORD fetched, i;
PWSTR object_ids[10];
GUID guid;
ULONGLONG capacity, free_space, capacity_objects, free_objects;
ULONG access, storage_type = WPD_STORAGE_TYPE_UNDEFINED;
LPWSTR storage_desc = NULL, st = NULL;
storage = PyList_New(0);
if (storage == NULL) { PyErr_NoMemory(); goto end; }
pyobject_raii storage(PyList_New(0));
if (!storage) return NULL;
Py_BEGIN_ALLOW_THREADS;
hr = device->Content(&content);
Py_END_ALLOW_THREADS;
if (FAILED(hr)) {hresult_set_exc("Failed to get content interface from device", hr); goto end;}
if (FAILED(hr)) {hresult_set_exc("Failed to get content interface from device", hr); return NULL;}
Py_BEGIN_ALLOW_THREADS;
hr = content->Properties(&properties);
Py_END_ALLOW_THREADS;
if (FAILED(hr)) {hresult_set_exc("Failed to get properties interface", hr); goto end;}
if (FAILED(hr)) {hresult_set_exc("Failed to get properties interface", hr); return NULL;}
Py_BEGIN_ALLOW_THREADS;
hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&storage_properties));
hr = storage_properties.CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL, CLSCTX_INPROC_SERVER);
Py_END_ALLOW_THREADS;
if (FAILED(hr)) {hresult_set_exc("Failed to create storage properties collection", hr); goto end;}
if (FAILED(hr)) {hresult_set_exc("Failed to create storage properties collection", hr); return NULL;}
Py_BEGIN_ALLOW_THREADS;
hr = storage_properties->Add(WPD_OBJECT_CONTENT_TYPE);
hr = storage_properties->Add(WPD_FUNCTIONAL_OBJECT_CATEGORY);
hr = storage_properties->Add(WPD_STORAGE_DESCRIPTION);
hr = storage_properties->Add(WPD_STORAGE_CAPACITY);
hr = storage_properties->Add(WPD_STORAGE_CAPACITY_IN_OBJECTS);
hr = storage_properties->Add(WPD_STORAGE_FREE_SPACE_IN_BYTES);
hr = storage_properties->Add(WPD_STORAGE_FREE_SPACE_IN_OBJECTS);
hr = storage_properties->Add(WPD_STORAGE_ACCESS_CAPABILITY);
hr = storage_properties->Add(WPD_STORAGE_FILE_SYSTEM_TYPE);
hr = storage_properties->Add(WPD_STORAGE_TYPE);
hr = storage_properties->Add(WPD_OBJECT_NAME);
Py_END_ALLOW_THREADS;
if (FAILED(hr)) {hresult_set_exc("Failed to create collection of properties for storage query", hr); goto end; }
#define A(what) hr = storage_properties->Add(what); if (FAILED(hr)) { hresult_set_exc("Failed to add storage property " #what " for storage query", hr); return NULL; }
A(WPD_OBJECT_CONTENT_TYPE);
A(WPD_FUNCTIONAL_OBJECT_CATEGORY);
A(WPD_STORAGE_DESCRIPTION);
A(WPD_STORAGE_CAPACITY);
A(WPD_STORAGE_CAPACITY_IN_OBJECTS);
A(WPD_STORAGE_FREE_SPACE_IN_BYTES);
A(WPD_STORAGE_FREE_SPACE_IN_OBJECTS);
A(WPD_STORAGE_ACCESS_CAPABILITY);
A(WPD_STORAGE_FILE_SYSTEM_TYPE);
A(WPD_STORAGE_TYPE);
A(WPD_OBJECT_NAME);
#undef A
Py_BEGIN_ALLOW_THREADS;
hr = content->EnumObjects(0, WPD_DEVICE_OBJECT_ID, NULL, &objects);
Py_END_ALLOW_THREADS;
if (FAILED(hr)) {hresult_set_exc("Failed to get objects from device", hr); goto end;}
if (FAILED(hr)) {hresult_set_exc("Failed to get objects from device", hr); return NULL;}
hr = S_OK;
while (hr == S_OK) {
wchar_t* object_ids[16] = {0};
Py_BEGIN_ALLOW_THREADS;
hr = objects->Next(10, object_ids, &fetched);
hr = objects->Next(arraysz(object_ids), object_ids, &fetched);
Py_END_ALLOW_THREADS;
if (SUCCEEDED(hr)) {
com_wchar_raii cleanup[arraysz(object_ids)];
for (i = 0; i < arraysz(object_ids); i++) { cleanup[i].set_ptr(object_ids[i]); };
for(i = 0; i < fetched; i++) {
CComPtr<IPortableDeviceValues> values;
Py_BEGIN_ALLOW_THREADS;
hr2 = properties->GetValues(object_ids[i], storage_properties, &values);
Py_END_ALLOW_THREADS;
if SUCCEEDED(hr2) {
if (SUCCEEDED(hr2)) {
if (
SUCCEEDED(values->GetGuidValue(WPD_OBJECT_CONTENT_TYPE, &guid)) && IsEqualGUID(guid, WPD_CONTENT_TYPE_FUNCTIONAL_OBJECT) &&
SUCCEEDED(values->GetGuidValue(WPD_FUNCTIONAL_OBJECT_CATEGORY, &guid)) && IsEqualGUID(guid, WPD_FUNCTIONAL_CATEGORY_STORAGE)
@ -146,28 +144,23 @@ PyObject* get_storage_info(IPortableDevice *device) { // {{{
values->GetUnsignedLargeIntegerValue(WPD_STORAGE_FREE_SPACE_IN_BYTES, &free_space);
values->GetUnsignedLargeIntegerValue(WPD_STORAGE_FREE_SPACE_IN_OBJECTS, &free_objects);
values->GetUnsignedIntegerValue(WPD_STORAGE_TYPE, &storage_type);
desc = Py_False;
if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_STORAGE_ACCESS_CAPABILITY, &access)) && access == WPD_STORAGE_ACCESS_CAPABILITY_READWRITE) desc = Py_True;
soid = PyUnicode_FromWideChar(object_ids[i], wcslen(object_ids[i]));
if (soid == NULL) { PyErr_NoMemory(); goto end; }
so = Py_BuildValue("{s:K, s:K, s:K, s:K, s:O, s:N}",
"capacity", capacity, "capacity_objects", capacity_objects, "free_space", free_space, "free_objects", free_objects, "rw", desc, "id", soid);
if (so == NULL) { PyErr_NoMemory(); goto end; }
if (SUCCEEDED(values->GetStringValue(WPD_STORAGE_DESCRIPTION, &storage_desc))) {
desc = PyUnicode_FromWideChar(storage_desc, wcslen(storage_desc));
if (desc != NULL) { PyDict_SetItemString(so, "description", desc); Py_DECREF(desc);}
CoTaskMemFree(storage_desc); storage_desc = NULL;
}
if (SUCCEEDED(values->GetStringValue(WPD_OBJECT_NAME, &storage_desc))) {
desc = PyUnicode_FromWideChar(storage_desc, wcslen(storage_desc));
if (desc != NULL) { PyDict_SetItemString(so, "name", desc); Py_DECREF(desc);}
CoTaskMemFree(storage_desc); storage_desc = NULL;
}
if (SUCCEEDED(values->GetStringValue(WPD_STORAGE_FILE_SYSTEM_TYPE, &storage_desc))) {
desc = PyUnicode_FromWideChar(storage_desc, wcslen(storage_desc));
if (desc != NULL) { PyDict_SetItemString(so, "filesystem", desc); Py_DECREF(desc);}
CoTaskMemFree(storage_desc); storage_desc = NULL;
}
PyObject *paccess = Py_False;
if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_STORAGE_ACCESS_CAPABILITY, &access)) && access == WPD_STORAGE_ACCESS_CAPABILITY_READWRITE) paccess = Py_True;
pyobject_raii soid(PyUnicode_FromWideChar(object_ids[i], -1));
if (!soid) return NULL;
pyobject_raii so(Py_BuildValue("{s:K, s:K, s:K, s:K, s:O, s:O}",
"capacity", capacity, "capacity_objects", capacity_objects, "free_space", free_space, "free_objects", free_objects, "rw", paccess, "id", soid.ptr()));
if (!so) return NULL;
#define A(which, key) { com_wchar_raii buf; if (SUCCEEDED(values->GetStringValue(which, buf.address()))) { \
pyobject_raii d(PyUnicode_FromWideChar(buf.ptr(), -1)); \
if (d) PyDict_SetItemString(so.ptr(), key, d.ptr()); \
else PyErr_Clear(); \
}}
A(WPD_STORAGE_DESCRIPTION, "description");
A(WPD_OBJECT_NAME, "name");
A(WPD_STORAGE_FILE_SYSTEM_TYPE, "filesystem");
#undef A
const wchar_t *st;
switch(storage_type) {
case WPD_STORAGE_TYPE_REMOVABLE_RAM:
st = L"removable_ram";
@ -184,26 +177,15 @@ PyObject* get_storage_info(IPortableDevice *device) { // {{{
default:
st = L"unknown_unknown";
}
desc = PyUnicode_FromWideChar(st, wcslen(st));
if (desc != NULL) {PyDict_SetItemString(so, "type", desc); Py_DECREF(desc);}
desc = NULL;
PyList_Append(storage, so);
Py_DECREF(so);
pyobject_raii dt(PyUnicode_FromWideChar(st, -1));
if (dt) PyDict_SetItemString(so.ptr(), "type", dt.ptr());
if (PyList_Append(storage.ptr(), so.ptr()) != 0) return NULL;
}
}
}
for (i = 0; i < fetched; i ++) { CoTaskMemFree(object_ids[i]); object_ids[i] = NULL;}
}// if(SUCCEEDED(hr))
}
ans = storage;
end:
if (content != NULL) content->Release();
if (objects != NULL) objects->Release();
if (properties != NULL) properties->Release();
if (storage_properties != NULL) storage_properties->Release();
if (values != NULL) values->Release();
return ans;
return storage.detach();
} // }}}
PyObject*
@ -219,7 +201,7 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
DWORD num_of_categories, i;
LPWSTR temp;
ULONG ti;
PyObject *t, *ans = NULL, *storage = NULL;
PyObject *t, *ans = NULL;
const char *type = NULL;
Py_BEGIN_ALLOW_THREADS;
@ -286,6 +268,7 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
// }
if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_DEVICE_TYPE, &ti))) {
type = "unknown";
switch (ti) {
case WPD_DEVICE_TYPE_CAMERA:
type = "camera"; break;
@ -299,8 +282,8 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
type = "personal information manager"; break;
case WPD_DEVICE_TYPE_AUDIO_RECORDER:
type = "audio recorder"; break;
default:
type = "unknown";
case WPD_DEVICE_TYPE_GENERIC:
break;
}
t = PyUnicode_FromString(type);
if (t != NULL) {
@ -353,20 +336,19 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
PyDict_SetItemString(ans, "has_storage", t);
if (t == Py_True) {
storage = get_storage_info(device);
if (storage == NULL) {
PyObject *exc_type, *exc_value, *exc_tb;
PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
if (exc_type != NULL && exc_value != NULL) {
PyErr_NormalizeException(&exc_type, &exc_value, &exc_tb);
PyDict_SetItemString(ans, "storage_error", exc_value);
Py_DECREF(exc_value); exc_value = NULL;
}
Py_XDECREF(exc_type); Py_XDECREF(exc_value); Py_XDECREF(exc_tb);
goto end;
}
PyDict_SetItemString(ans, "storage", storage);
pyobject_raii storage(get_storage_info(device));
if (!storage) {
pyobject_raii exc_type, exc_value, exc_tb;
PyErr_Fetch(exc_type.address(), exc_value.address(), exc_tb.address());
if (exc_type) {
PyErr_NormalizeException(exc_type.address(), exc_value.address(), exc_tb.address());
PyDict_SetItemString(ans, "storage_error", exc_value.ptr());
} else {
PyDict_SetItemString(ans, "storage_error", PyUnicode_FromString("get_storage_info() failed without an error set"));
}
} else {
PyDict_SetItemString(ans, "storage", storage.ptr());
}
}
Py_BEGIN_ALLOW_THREADS;

View File

@ -45,7 +45,9 @@ class wchar_raii {
}
wchar_t *ptr() { return handle; }
wchar_t *detach() { wchar_t *ans = handle; handle = NULL; return ans; }
void set_ptr(wchar_t *val) { handle = val; }
wchar_t **address() { return &handle; }
explicit operator bool() const { return handle != NULL; }
};
@ -67,6 +69,8 @@ class com_wchar_raii {
}
wchar_t *ptr() { return handle; }
void set_ptr(wchar_t *val) { handle = val; }
wchar_t *detach() { wchar_t *ans = handle; handle = NULL; return ans; }
wchar_t **address() { return &handle; }
explicit operator bool() const { return handle != NULL; }
};