~ubuntu-branches/ubuntu/karmic/calibre/karmic

« back to all changes in this revision

Viewing changes to src/calibre/utils/windows/winutil.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730124941-qjdsmri25zt8zocn
Tags: 0.6.3+dfsg-0ubuntu1
* New upstream release. Please see http://calibre.kovidgoyal.net/new_in_6/
  for the list of new features and changes.
* remove_postinstall.patch: Update for new version.
* build_debug.patch: Does not apply any more, disable for now. Might not be
  necessary any more.
* debian/copyright: Fix reference to versionless GPL.
* debian/rules: Drop obsolete dh_desktop call.
* debian/rules: Add workaround for weird Python 2.6 setuptools behaviour of
  putting compiled .so files into src/calibre/plugins/calibre/plugins
  instead of src/calibre/plugins.
* debian/rules: Drop hal fdi moving, new upstream version does not use hal
  any more. Drop hal dependency, too.
* debian/rules: Install udev rules into /lib/udev/rules.d.
* Add debian/calibre.preinst: Remove unmodified
  /etc/udev/rules.d/95-calibre.rules on upgrade.
* debian/control: Bump Python dependencies to 2.6, since upstream needs
  it now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
271
271
        // Loop for all drives (MAX_DRIVES = 26)
272
272
 
273
273
 
274
 
    for(nLoopIndex = 0; nLoopIndex< MAX_DRIVES; nLoopIndex++)
 
274
    for(nLoopIndex = 0; nLoopIndex < MAX_DRIVES; nLoopIndex++)
275
275
    {
276
276
        // if a drive is present,
277
277
                if(dwDriveMask & 1)
306
306
 
307
307
}
308
308
 
 
309
static DEVINST 
 
310
GetDrivesDevInstByDeviceNumber(long DeviceNumber,
 
311
          UINT DriveType, LPWSTR szDosDeviceName)
 
312
{
 
313
    GUID *guid;
 
314
    HDEVINFO hDevInfo;
 
315
    DWORD dwIndex, dwBytesReturned;
 
316
    BOOL bRet, IsFloppy;
 
317
    BYTE Buf[1024];
 
318
    PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;
 
319
    long res;
 
320
    HANDLE hDrive;
 
321
    STORAGE_DEVICE_NUMBER sdn;
 
322
    SP_DEVICE_INTERFACE_DATA         spdid;
 
323
    SP_DEVINFO_DATA                  spdd;
 
324
    DWORD                            dwSize;
 
325
 
 
326
 
 
327
    IsFloppy = (wcsstr(szDosDeviceName, L"\\Floppy") != NULL); // is there a better way?
 
328
 
 
329
    switch (DriveType) {
 
330
    case DRIVE_REMOVABLE:
 
331
        if ( IsFloppy ) {
 
332
        guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
 
333
        } else {
 
334
        guid = (GUID*)&GUID_DEVINTERFACE_DISK;
 
335
        }
 
336
        break;
 
337
    case DRIVE_FIXED:
 
338
        guid = (GUID*)&GUID_DEVINTERFACE_DISK;
 
339
        break;
 
340
    case DRIVE_CDROM:
 
341
        guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
 
342
        break;
 
343
    default:
 
344
        PyErr_SetString(PyExc_ValueError, "Invalid drive type");
 
345
        return 0;
 
346
    }
 
347
 
 
348
    // Get device interface info set handle
 
349
    // for all devices attached to system
 
350
    hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL,
 
351
                        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 
352
 
 
353
    if (hDevInfo == INVALID_HANDLE_VALUE)  {
 
354
        PyErr_SetString(PyExc_ValueError, "Invalid handle value");
 
355
        return 0;
 
356
    }
 
357
 
 
358
    // Retrieve a context structure for a device interface
 
359
    // of a device information set.
 
360
    dwIndex = 0;
 
361
    bRet = FALSE;
 
362
 
 
363
    
 
364
    pspdidd =  (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
 
365
    spdid.cbSize = sizeof(spdid);
 
366
 
 
367
    while ( TRUE )  {
 
368
        bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL,
 
369
            guid, dwIndex, &spdid);
 
370
        if ( !bRet ) {
 
371
        break;
 
372
        }
 
373
 
 
374
        dwSize = 0;
 
375
        SetupDiGetDeviceInterfaceDetail(hDevInfo,
 
376
        &spdid, NULL, 0, &dwSize, NULL);
 
377
 
 
378
        if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
 
379
        pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
 
380
 
 
381
        ZeroMemory((PVOID)&spdd, sizeof(spdd));
 
382
        spdd.cbSize = sizeof(spdd);
 
383
 
 
384
        res =
 
385
            SetupDiGetDeviceInterfaceDetail(hDevInfo, &
 
386
                                            spdid, pspdidd,
 
387
                                            dwSize, &dwSize,
 
388
                                            &spdd);
 
389
        if ( res ) {
 
390
            hDrive = CreateFile(pspdidd->DevicePath,0,
 
391
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
 
392
                        NULL, OPEN_EXISTING, 0, NULL);
 
393
            if ( hDrive != INVALID_HANDLE_VALUE ) {
 
394
            dwBytesReturned = 0;
 
395
            res = DeviceIoControl(hDrive,
 
396
                            IOCTL_STORAGE_GET_DEVICE_NUMBER,
 
397
                            NULL, 0, &sdn, sizeof(sdn),
 
398
                            &dwBytesReturned, NULL);
 
399
            if ( res ) {
 
400
                if ( DeviceNumber == (long)sdn.DeviceNumber ) {
 
401
                CloseHandle(hDrive);
 
402
                SetupDiDestroyDeviceInfoList(hDevInfo);
 
403
                return spdd.DevInst;
 
404
                }
 
405
            }
 
406
            CloseHandle(hDrive);
 
407
            }
 
408
        }
 
409
        }
 
410
        dwIndex++;
 
411
    }
 
412
 
 
413
    SetupDiDestroyDeviceInfoList(hDevInfo);
 
414
    PyErr_SetString(PyExc_ValueError, "Invalid device number");
 
415
 
 
416
    return 0;
 
417
}
 
418
 
 
419
 
 
420
 
 
421
static BOOL
 
422
eject_drive_letter(WCHAR DriveLetter) {
 
423
    LPWSTR szRootPath = L"X:\\", 
 
424
           szDevicePath = L"X:", 
 
425
           szVolumeAccessPath = L"\\\\.\\X:";
 
426
    WCHAR  szDosDeviceName[MAX_PATH];
 
427
    long DeviceNumber, res, tries;
 
428
    HANDLE hVolume; 
 
429
    STORAGE_DEVICE_NUMBER sdn;
 
430
    DWORD dwBytesReturned;
 
431
    DEVINST DevInst;
 
432
    ULONG Status;
 
433
    ULONG ProblemNumber;
 
434
    UINT DriveType;
 
435
    PNP_VETO_TYPE VetoType;
 
436
    WCHAR VetoNameW[MAX_PATH];
 
437
    BOOL bSuccess;
 
438
    DEVINST DevInstParent;
 
439
    
 
440
    szRootPath[0] = DriveLetter;
 
441
    szDevicePath[0] = DriveLetter;
 
442
    szVolumeAccessPath[4] = DriveLetter;
 
443
 
 
444
    DeviceNumber = -1;
 
445
 
 
446
    hVolume = CreateFile(szVolumeAccessPath, 0,
 
447
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
 
448
                        NULL, OPEN_EXISTING, 0, NULL);
 
449
    if (hVolume == INVALID_HANDLE_VALUE) {
 
450
        PyErr_SetString(PyExc_ValueError, "Invalid handle value for drive letter");
 
451
        return FALSE;
 
452
    }
 
453
 
 
454
    dwBytesReturned = 0;
 
455
    res = DeviceIoControl(hVolume,
 
456
                        IOCTL_STORAGE_GET_DEVICE_NUMBER,
 
457
                        NULL, 0, &sdn, sizeof(sdn),
 
458
                        &dwBytesReturned, NULL);
 
459
    if ( res ) {
 
460
        DeviceNumber = sdn.DeviceNumber;
 
461
    }
 
462
    CloseHandle(hVolume);
 
463
 
 
464
    if ( DeviceNumber == -1 ) {
 
465
        PyErr_SetString(PyExc_ValueError, "Can't find drive number");
 
466
        return FALSE;
 
467
    }
 
468
 
 
469
    res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
 
470
    if ( !res ) {
 
471
       PyErr_SetString(PyExc_ValueError, "Can't find dos device");
 
472
       return FALSE;
 
473
    }
 
474
 
 
475
    DriveType = GetDriveType(szRootPath);
 
476
 
 
477
    DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber,
 
478
                  DriveType, szDosDeviceName);
 
479
    if (DevInst == 0) return FALSE;
 
480
 
 
481
    DevInstParent = 0;
 
482
    Status = 0;
 
483
    ProblemNumber = 0;
 
484
    bSuccess = FALSE;
 
485
 
 
486
    res = CM_Get_Parent(&DevInstParent, DevInst, 0);
 
487
 
 
488
    for ( tries = 0; tries < 3; tries++ ) {
 
489
        VetoNameW[0] = 0;
 
490
 
 
491
        res = CM_Request_Device_EjectW(DevInstParent,
 
492
                &VetoType, VetoNameW, MAX_PATH, 0);
 
493
 
 
494
        bSuccess = (res==CR_SUCCESS &&
 
495
                            VetoType==PNP_VetoTypeUnknown);
 
496
        if ( bSuccess )  {
 
497
            break;
 
498
        }
 
499
 
 
500
        Sleep(500); // required to give the next tries a chance!
 
501
    }
 
502
    if (!bSuccess)  PyErr_SetString(PyExc_ValueError, "Failed to eject drive after three tries");
 
503
    return bSuccess;
 
504
}
 
505
 
 
506
static PyObject *
 
507
winutil_eject_drive(PyObject *self, PyObject *args) {
 
508
    char DriveLetter;
 
509
 
 
510
    if (!PyArg_ParseTuple(args, "c", &DriveLetter)) return NULL;
 
511
 
 
512
    if (!eject_drive_letter((WCHAR)DriveLetter)) return NULL;
 
513
    Py_RETURN_NONE;
 
514
}
 
515
 
 
516
 
309
517
PSP_DEVICE_INTERFACE_DETAIL_DATA
310
518
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id,
311
519
                       BOOL *iterate) {
697
905
be a unicode string. Returns unicode strings."
698
906
     },
699
907
 
 
908
        {"eject_drive", winutil_eject_drive, METH_VARARGS,
 
909
                        "eject_drive(drive_letter)\n\nEject a drive. Raises an exception on failure."
 
910
        },
 
911
 
700
912
    {NULL, NULL, 0, NULL}
701
913
};
702
914