Thursday, May 23, 2013

cygwin如何编译不依赖cygwin1.dll的程序

g++ -o /cygdrive/d/temp/client.exe /cygdrive/d/temp/main.cpp -mno-cygwin
    g++: The -mno-cygwin flag has been removed; use a mingw-targeted cross-compiler.

网上有人建议用i686-pc-cygwin-gcc/++-4.exe替换g++,我试了一下,还是一样的错误。

目前有个折中的方案,就是采用g++3而非4,于是运行/usr/bin/set-gcc-default-3.sh然后再编译,OK,通过。

Saturday, May 18, 2013

系统进程和系统线程

系统进程即为ID = 4的名为"System"的进程,系统线程即所有运行于系统进程中的线程,驱动程序的DriverEntry即运行于系统线程之中。如果要创建系统线程,只要设置PsCreateSystemThread的ProcessHandle为NULL就行(使用PsCreateSystemThread创建线程需要特别注意的是线程函数,线程函数的最后一行通常是PsTerminateSystemThread(STATUS_))。

WaitForMultipleObjects 和 KeWaitForMultipleObjects 备忘

WaitForMultipleObjects 和 KeWaitForMultipleObjects 备忘
联系起来看这两个函数才能真正搞明白,先看内核函数,再看API


NTSTATUS
  KeWaitForMultipleObjects(
    IN ULONG  Count,
    IN PVOID  Object[],
    IN WAIT_TYPE  WaitType,
    IN KWAIT_REASON  WaitReason,
    IN KPROCESSOR_MODE  WaitMode,
    IN BOOLEAN  Alertable,
    IN PLARGE_INTEGER  Timeout  OPTIONAL,
    IN PKWAIT_BLOCK  WaitBlockArray  OPTIONAL
    );
KeWaitForMultipleObjects can return one of the following:

STATUS_SUCCESS
The caller specified WaitAll for the WaitType parameter and all dispatcher objects in the Object array have been set to the signaled state.
STATUS_ALERTED
The wait was interrupted to deliver an alert to the calling thread.
STATUS_USER_APC
The wait was interrupted to deliver a user asynchronous procedure call (APC) to the calling thread.
STATUS_TIMEOUT
A time-out occurred before the specified set of wait conditions was met. This value can be returned when an explicit time-out value of zero is specified, but the specified set of wait conditions cannot be met immediately.
STATUS_WAIT_0 through STATUS_WAIT_63
The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state. The lower six bits of the return value encode the zero-based index of the object that satisfied the wait.
STATUS_ABANDONED_WAIT_0 through STATUS_ABANDONED_WAIT_63
The caller attempted to wait for a mutex that has been abandoned. The lower six bits of the return value encode the zero-based index of the mutex in the Object array.

Note that the NT_SUCCESS macro recognizes all of these status values as "success" values.



DWORD WINAPI WaitForMultipleObjects(
  __in  DWORD nCount,   
  __in  const HANDLE* lpHandles,
  __in  BOOL bWaitAll,
  __in  DWORD dwMilliseconds
);
nCount表明想要等待的对象个数,最大值MAXIMUM_WAIT_OBJECTS(0x40)。它满足:
    0 < MAXIMUM_WAIT_OBJECTS < WAIT_ABANDONED_0
后面会介绍原因。
lpHandles表明想要等待的对象数组,可以等待的对象有事件、信号量(注意一个信号量中有很多信号灯)、互斥量、线程,Process,Console input and so on。

If the function succeeds, the return value indicates the event that caused the function to return. It can be one of the following values. (Note that WAIT_OBJECT_0 is defined as 0 and WAIT_ABANDONED_0 is defined as 0x00000080L.):
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount– 1) =>
If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled.
If bWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the lpHandles array index of the object that satisfied the wait. If more than one object became signaled during the call, this is the array index of the signaled object with the smallest index value of all the signaled objects.

WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount– 1) =>
If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled and at least one of the objects is an abandoned mutex object(see KeWaitForMultipleObjects for detail).
If bWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lpHandles array index of an abandoned mutex object that satisfied the wait. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.

If a mutex was protecting persistent state information, you should check it for consistency.

使用信号灯同步线程

#include <windows.h> 
#include <process.h>  // _beginthread, _endthread 
#include <stdio.h> 
 
/*
 * 可以理解信号灯内部有N个灯泡。
 * 如果有一个灯泡亮着,就代表信号灯处于激发状态,如果全灭,则代表信号灯处于未激发状态。
 */ 
 
// 创建线程 
UINT WINAPI Thread1(LPVOID para) 

    printf("进入Thread1......\n"); 
    HANDLE* phSemaphore = (HANDLE*)para; 
 
    printf("将等待5秒......\n"); 
    // 等待5秒 
    Sleep(5000); 
 
    printf("离开Thread1......\n"); 
 
    // 参数1:信号灯句柄 
    // 参数2:本次操作增加的计数 
    // 参数3:记录以前的计数 
    // 将信号灯计数器加1,是之处于激发状态 
    ReleaseSemaphore(*phSemaphore, 1, NULL); 
    return 0; 

 
int main() 

    /*
     * 信号灯计数为0时,信号灯为nonsingled状态。
     * 也就是说这时用WaitForSingleObject时会等待直到当前数大于0(或超时),
     * 如果不为0时,用WaitForSingleObject就马上返回并把当前数减一;
     */ 
    // 参数1:LPSECURITY_ATTRIBUTES pEventAttributes 安区参数 一般用户不用考虑它,传入NULL。 
    // 参数2:初始化计数个数。 
    // 参数3:计数器最大个数。 
    // 参数4:指定事件的对象的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。名字是对大小写敏感的。 
    // 创建同步事件 
    HANDLE hSemaphore = CreateSemaphore(NULL, 2, 2, NULL);  // 将传入Thread1的参数 
 
    // 此时的信号灯计数为2,处于触发状态 
    WaitForSingleObject(hSemaphore, INFINITE); 
    // 此时的信号灯计数为1,处于触发状态 
    WaitForSingleObject(hSemaphore, INFINITE); 
    // 此时的信号灯计数为0,处于未触发状态 
 
 
    // 第1个参数:安全属性,NULL为默认安全属性 
    // 第2个参数:指定线程堆栈的大小。如果为0,则线程堆栈大小和创建它的线程的相同。一般用0 
    // 第3个参数:指定线程函数的地址,也就是线程调用执行的函数地址(用函数名称即可,函数名称就表示地址) 
    // 第4个参数:传递给线程的参数的指针,可以通过传入对象的指针,在线程函数中再转化为对应类的指针 
    // 第5个参数:线程初始状态,0:立即运行;CREATE_SUSPEND:suspended(悬挂) 
    // 第6个参数:用于记录线程ID的地址 
    // 开启新线程,并将同步事件句柄指针传递给新线程 
    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, Thread1, &hSemaphore, 0, NULL); 
    // 等待该事件激发 
    WaitForSingleObject(hSemaphore, INFINITE); 
    CloseHandle(hThread);   // 关闭内核对象 
    system("PAUSE"); 
    return 0; 
}

Thursday, May 16, 2013

Concepts of Digital Signature and Windows Code Signing

Authenticode:
software publishers use authenticode to sign either a file or a collection of files(such as a driver package)

Microsoft Authenticode:
Authenticode belong to MS. (I believe it's a key which must be safely saved by microsoft)

digital certificate:
Also refered as signing certificate or authenticode certificate, it identify a publisher(exactly, the signer) and the issuer(CA) and it at least contains a public key and an authenticode. (I believe the info about the public key can be queried from CA)

thumbprint:
a (cryptographic) hash of a file(sha256? or something else?) or a package, the thumbprint can be used as the source of private key.

digital signature:
windows first calc the thumbprint of the file, then use the pulic key(public key and its publisher must previous verified) to decry the digital signature, if they two match, the digital signature is OK.

Trusted Publishers certificate store:
HKEY_LOCAL_MACHINE
   Software
      Microsoft
         SystemCertificates
        TrustedPublisher

or the curr user:
HKCU
   Software
      Microsoft
         SystemCertificates
        TrustedPublisher
 and all certificates in HKEY_LOCAL_MACHINE are inherited by current user

Trusted Root Certification Authorities certificate store:
HKEY_LOCAL_MACHINE
   Software
      Microsoft
         SystemCertificates
        CA

Refer:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff543743%28v=vs.85%29.aspx
http://technet.microsoft.com/en-us/library/cc962021.aspx
http://office.microsoft.com/en-us/excel-help/how-to-tell-if-a-digital-signature-is-trustworthy-HA001230875.aspx : How to tell if a digital signature of Office doc is trustworthy

设备读写方法小结

DO_BUFFERED_IO法:
    在IoCreateDev的时候需要设置返回的设备对象的pDevObj->Flags |= DO_BUFFERED_IO

    由于所有进程共享高2G/1G的虚拟内存,为了避免进程切换带来的风险,所以用户在WriteFile中提供的缓冲区需要被拷贝到内核模式下的缓冲区中,该缓冲区就是AssociatedIRP.SystemBuffer子域,当前层驱动需要读写该缓冲区的多少字节由该层IO_STACK_LOCATION中的Paraments.Read.Length/Paraments.Write.Length决定。
    至于实际读写到多少字节,由IRP的IoStatus.Information设置

DO_DIRECT_IO法:
   //确定pDevObj->Flags是DO_DIRECT_IO
   IrpSp = IoGetCurrentIrpStackLocation(Irp);
   ReadLength = IrpSp->Parameters.Read.Length;
   MdlLength = MmGetMdlByteCount(Irp->MdlAddress);
   //确定ReadLength == MdlLength
   MdlOffset = MmGetMdlByteOffset(Irp->MdlAddress);
   //缓冲区的虚拟地址
   MdlAddress = MmGetMdlVirtualAddress(Irp->MdlAddress); //MdlAddress == MdlAddress->StartVA + MdlAddress->ByteOffset
   //获得虚拟缓冲区在内核模式下的映射地址
   KernelAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress);
  
   //设置KernelAddress的内容;
   //笔者曾经做过实验:给定一个足够大的ReadLength,memset都能正常工作, 可见映射地址是连续内存
   memset(KernelAddress,0xAB,MdlLength)

       Irp->IoStatus.Status = STATUS_SUCCESS;

       Irp->IoStatus.Information = ReadLength;

       IoCompleteRequest(Irp,IO_NO_INCREMENT);

其他方法:
    直接访问Irp->UserBuffer,这种方法很危险,所以要访问UserBuffer的时候,先用ProbeForWrite/ProbeForRead探测一下,如果这两个函数抛出异常,代表不可访问,读写失败。

设备在创建的时候,其读写方法(应该)就是上述三种方法之一。但是这里有一个"矛盾"的地方,为了说明问题,必须先详细介绍以下函数:
BOOL WINAPI DeviceIoControl(
  __in         HANDLE hDevice,
  __in         DWORD dwIoControlCode,
  __in_opt     LPVOID lpInBuffer,
  __in         DWORD nInBufferSize,
  __out_opt    LPVOID lpOutBuffer,
  __in         DWORD nOutBufferSize,
  __out_opt    LPDWORD lpBytesReturned,
  __inout_opt  LPOVERLAPPED lpOverlapped
);
现在介绍dwIoControlCode,程序员可以直接用系统预定义的值(winioctl.h,比如IOCTL_DISK_FORMAT_TRACKS),也可以按照如下规范定义:
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
DeviceType
    Identifies the device type. This value must match the value that is set in the DeviceType member of the driver's DEVICE_OBJECT structure.
FunctionCode
    Identifies the function to be performed by the driver. Values of less than 0x800 are reserved for Microsoft. Values of 0x800 and higher can be used by vendors.
TransferType
    Indicates how the system will pass data between the caller of DeviceIoControl (or IoBuildDeviceIoControlRequest) and the driver that handles the IRP. Use one of the following system-defined constants:
    METHOD_BUFFERED
    METHOD_IN_DIRECT or METHOD_OUT_DIRECT
    METHOD_NEITHER

读者可能已经发现,DeviceIoControl有两个缓冲区需要设置读写方式,那么TransferType就需要包含这两个信息,在驱动中需要这么处理:
如果TransferType==METHOD_BUFFERED,那么输入输出都采用AssociatedIRP.SystemBuffer,(ZXXU: 这个buf的长度要求是MAX(nInBufferSize,nOutBufferSize)
如果TransferType==METHOD_IN_DIRECT(暗示hDevice是以读方式打开),那么输入采用AssociatedIRP.SystemBuffer,输出采用MDL;METHOD_OUT_DIRECT同理
如果TransferType==METHOD_NEITHER,那么输入缓冲区采用Parameters.DeviceIoControl.Type3InputBuffer表示,输出采用Irp->UserBuffer

Monday, May 13, 2013

物理内存、虚拟内存、共享内存


如果某物理内存页既映射到进程A的虚拟内存中,也映射到进程B的虚拟内存中,那么该内存页即为进程间共享内存。

对32位应用程序而言,所有进程的高2G或者高1G的虚拟内存的映射方式完全一致。

虚拟内存按照是否可以swap出去,可以分为分页内存和非分页内存, 非分页内存可以在各个中断请求级上用,分页内存只能用在DISPATCH_LEVEL(不包括)之下的请求级。以下是这两种内存的使用方法:

#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")

#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")
  

#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
 


另外,分配内存的时候可以指定是分配哪种内存:
ExAllocatePool(PagedPool, 1024)


WDM分层模型

WDM为分层驱动模型,至少两层,下层控制PDOs,上层控制FDOs,还可以有若干过滤驱动,同一层的DOs有相同的StackSize域(物理层的StackSize总是为1),即当前设备栈的大小。

具体到任何一个物理设备或者虚拟设备,它的每一层DO构成它的设备栈,该设备栈为通过AttachedDevice联系的链栈,链首为PDO。要将当前设备压栈,需要使用PDEVICE_OBJECT
  PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
    IN PDEVICE_OBJECT  SourceDevice,
    IN PDEVICE_OBJECT  TargetDevice
    );
函数,该函数的SourceDevice可以是链栈中任何一个对象,返回的一定是栈顶的对象(详见MSDN和张帆的HelloWDM).

为了更好地查看链栈,请翻阅<<张帆P110>>的DeviceTree:
首先由Driver\PnpManager创建\Device\00000040(PDO),然后有一个 \Device\MyWDMDevice附加在其上(注意\Device\MyWDMDevice的命名管理方式并不好,最好是\Device\MyWDMDevice1,\Device\MyWDMDevice2。。。,因为系统中可能有多个FDO设备)。

Sunday, May 12, 2013

AttachedDevice和NextDevice

VOID DetachSomeDevFromTargetDriver(PDRIVER_OBJECT pOwnerDrvObject)
{
PDEVICE_OBJECT pDevObj,pNextDev;

if (pOwnerDrvObject)
{
   //取第一个设备
   pNextDev=pOwnerDrvObject->DeviceObject;
   do
   {
    pDevObj=pNextDev;
   
while(pDevObj->AttachedDevice)
    {

     if (IsSomeDevice(pDevObj->AttachedDevice))
     {
      DbgPrint("Detaching Device:0x%08X\n",pDevObj->AttachedDevice);
      IoDetachDevice(pDevObj);     }
     else
     {
      pDevObj=pDevObj->AttachedDevice;//若不是,取上一层设备
     }
    }
    pNextDev=pNextDev->NextDevice;
   } while(pNextDev);
}
}

DriverEntry


NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath):
    _DRIVER_OBJECT:
        DriverName: 一般为\Driver\<驱动名称>(与设备命名规则类似:\Device\<设备名称>)
        PUNICODE_STRING HardwareDatabase:指向注册表中硬件配置信息的路径,用Unicode字符串表示。该字符串内容一般为\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM。
    RegistryPath:
8660f008  5c 00 52 00 45 00 47 00-49 00 53 00 54 00 52 00  \.R.E.G.I.S.T.R.
8660f018  59 00 5c 00 4d 00 41 00-43 00 48 00 49 00 4e 00  Y.\.M.A.C.H.I.N.
8660f028  45 00 5c 00 53 00 59 00-53 00 54 00 45 00 4d 00  E.\.S.Y.S.T.E.M.
8660f038  5c 00 43 00 6f 00 6e 00-74 00 72 00 6f 00 6c 00  \.C.o.n.t.r.o.l.
8660f048  53 00 65 00 74 00 30 00-30 00 31 00 5c 00 53 00  S.e.t.0.0.1.\.S.
8660f058  65 00 72 00 76 00 69 00-63 00 65 00 73 00 5c 00  e.r.v.i.c.e.s.\.
8660f068  48 00 65 00 6c 00 6c 00-6f 00 57 00 44 00 4d 00  H.e.l.l.o.W.D.M.

节选自<<张帆>>:驱动加载的时候,系统进程启动新的线程,利用对象管理器创建_DRIVER_OBJECT,利用配置管理器获取RegistryPath(如果以后想用这个字符串,需要复制到安全的地方)

 

Friday, May 10, 2013

Aeroplan简介


 
Groupe Aeroplan started to conduct business under the new brand name Aimia. While the names and brand identities of our consumer facing brands Aeroplan in Canada, Nectar in Chile, Italy and the UK, and so on
 
通过加拿大航空或者合作联盟购票可以获得积分((订往返可以获得更多积分)
预定酒店、乘船、租车、泊车、渡假套餐、火车旅行(与Rail Europe合作)、商场购物等可以获得积分(需要有合作关系)

aeroplan配置可以上aeroplan.com/profile

aeroplan的合作者可以上aeroplan.com/earnmiles查。

aeroplan使用积分可以上aeroplan.com/useyourmiles

Sunday, May 5, 2013

DosDevices

DosDevices
there is one global \DosDevices directory and multiple local \DosDevices directories.The global \DosDevices directory holds the MS-DOS device names that are visible system-wide.A local \DosDevices directory holds MS-DOS device names that are visible only in a particular local DosDevices context(see below to understand local DosDevices context).

each logon session has its own local DosDevices context,If a user mounts a network drive as X:, only himself can see this。

Each thread has a current DosDevices context, which can change over the lifetime of a thread.

when the object manager looks up a name in \DosDevices, it first searches the local \DosDevices directory, and then the global \DosDevices directory.

A driver that must create its MS-DOS device names in the global \DosDevices directory can do so by creating its symbolic links in a standard driver routine that is guaranteed to run in a system thread context, such as DriverEntry{RtlInitUnicodeString(&symbolicLinkName, L"\\DosDevices\\Global\\SymbolicLinkName");}.
When a thread in a particular local DosDevices context sends an IOCTL, the driver's DispatchDeviceControl is called from within the current thread context. A driver can create MS-DOS device names in a local \DosDevices directories by creating the symbolic link in response to the IOCTL.

On Windows XP and later, local \DosDevices directories are identified by the AuthenticationID for the logon session's access token.

Windows驱动编写注意事项

有些C语言运行时函数如strcpy可以用在驱动中(因为该函数不依赖Windows API实现),但是建议使用内核态的运行时函数。

C++可以实现操作符重载,所以重载的new操作符有可能用在驱动中,但是驱动开发不建议使用C++.

开发时尽量采用checked版本,这样可以用windbg进行源码级调试

makefile文件一般只包含一行(!INCLUDE $(NTMAKEENV)\makefile.def)即可,如果要修改请参考ms-help://MS.WDK.v10.7600.090618.01/DevTest_g/hh/DevTest_g/Build_Ref_31c38413-df20-4483-aa9c-16353d9d82fa.xml.htm或者在wdk中搜索MAKEFILE.INC然后链接过去

如果不明确规定,当前目录下所有源码都会被编译,否则可以编写dirs文件,下面是一个例子:
    DIRS= \
         1394 \
         audio \
         AVStream \
         biometrics
dirs文件和sources文件配合使用,详见ms-help://MS.WDK.v10.7600.090618.01/DevTest_g/hh/DevTest_g/Build_Ref_78947534-363a-4a43-bc39-5e26c9c05449.xml.htm或者在wdk中搜索TARGETNAME后链接过去

还有一个MAKEFILE.INC可选文件,在wdk中搜索MAKEFILE.INC可以获得帮助信息

由于DbgPrint无法在FreeBuild中使用,所以建议使用KdPrint,该宏定义如下:
#if DBG
#define KdPrint(_x_) DbgPrint _x_
#else
#define KdPrint(_x_)
#endif
所以KdPrint((_x_))会转成DbgPrint(_x_),如果用KdPrint(_x_)则会出错。

符号链接最好用"\?\"的形式,为了兼容以前的驱动,'\DosDevices\'的形式在逻辑是等效的,从应用程序中访问驱动用"\.\"的形式。

如果驱动需要频繁地分配和回收固定大小的内存,为了避免产生内存碎片,windows提供了Lookaside内存。

RtlCopyMemory用于源和目标内存不重合的情况,RtlMoveMemory用于二者有交叉的情况,二者的关系相当于memcpy和memmove





Friday, May 3, 2013

windows架构综述

首先声明,本文并非原创,只是对大牛先辈们的文章的收集整理,如有错误,欢迎指正。另外,如无特别说明,本文的概念都适用于32位的windows xp和windows 2003(其他的我不知道)。

Ring3层:
即应用层,该层的应用程序使用各自的子系统进行编程,最核心的子系统是Win32子系统,其他子系统如Posix的API最终要转化为Win32 API;最值得一提的是Wow(windows on windows)子系统,该子系统是为了16位windows程序而设计(同理,该子系统下的程序最终转化为Win32调用)。

Win32 API主要分为三类:User函数(管理图形组件如窗体、菜单、按钮)、GDI函数(提供函数在物理设备上画图)、KERNEL函数(管理进程、文件和通信等)。不管哪类API,都要转化为Native API,(所有)Native API都定义在Ntdll.dll中。NativeAPI通过int 2e(或者sysenter)软中断进行系统调用, 它定义在Ring3,是进入Ring0的窗口。

系统调用会存放在两个表中,第一个是SSDT(KeServiceDescriptorTable),第二个是Shadow SSDT(KeServiceDescriptorTableShadow),前者实现KERNEL函数需要的功能(在ntoskrnl.exe、ntkrnlmp.exe(对称处理器)、ntkrnlpa.exe(物理地址扩展)或者ntkrpamp.exe中),后者实现User函数和GDI函数的功能(放在win32k.sys,后者应该是前者的超集)。Native API通常由Zw或者Nt开头,与系统调用的名字相同(Zw和Nt开头函数在r3(ntdll)中的定义是完全一致的,但在r0中,Nt开头的函数是真正的实现,Zw开头的函数通过SSDT调用其对应的Nt函数)。

Ring0层:
Ring0层分为执行体、内核和驱动程序。

执行体分为对象管理器、进程管理器、虚拟内存管理器、I/O管理器和配置管理器。
对象管理器管理Windows定义的某些数据结构的创建、管理和回收,这些结构中的某些成员可以被读写,相当于公有成员,其他的相当于私有成员,对象管理器提供例程来访问私有成员。
I/O管理器负责创建IRP(IO请求包),IRP由用户或者系统发起,由IO管理器创建,由驱动程序响应(当然,驱动也可以进一步创建IRP给更底层的驱动)。
配置管理器管理注册表。

和执行体相比,内核是非常小的,它主要提供如下功能:
线程调度
对多处理器同步
对中断、异常和陷阱响应

驱动程序用来操作设备。有些设备是虚拟出来的比如虚拟光驱设备,有些设备是真实设备派生出来的设备,比如卷设备,一个分区对应一个卷设备,所有对卷设备的操作由卷驱动最终转化为对磁盘驱动的请求。

Sunday, April 28, 2013

generator in python

class GeneratorDemoException(Exception):
    def __str__(self):
        return "GeneratorDemoException occured"

def generator_demo():
    ret_1 = yield "demo of generator:"
    print "ret_1=",ret_1
    ret_2 = yield "call me with send(arg) then I set ret_1 with arg"
    print "ret_2=",ret_2
   
    try:
        ret_3 = yield "call me with next() and I always set ret_2 as None"
    except GeneratorDemoException,e:
        ret_3 = "failed to yield"
    print "ret_3=",ret_3
   
generator = generator_demo()
print generator.next()
print generator.send("arg_to_set_ret1")
print generator.next()
try:
    ret_from_throw = generator.throw(GeneratorDemoException,"test finished")
except:
    pass
   

Thursday, April 25, 2013

__hash__ in python

__hash__() should return an integer. The only required property is that objects which compare equal have the same hash value; it is advised to somehow mix together the hash values for the components of the object that also play a part in comparison of objects

If a class defines mutable objects, it should not implement __hash__(), since hashable collection implementations require that a object's hash value is immutable
__hash__ may now be set to None to explicitly flag instances of a class as unhashable,此外,为了保证对象的哈希的唯一性,一般来说:
def __hash__(self):
    return id(self)

Tuesday, April 23, 2013

Coercion rules in python[summary]

if the left operand is an instance of a built-in type or a new-style class, and
the right operand is an instance of a proper subclass of that type or class and overrides the base’s __rop__()
method, the right operand’s __rop__() method is tried before the left operand’s __op__() method.

When an in-place operator (like ‘+=‘) is used, if the left operand implements __iop__(), it is invoked without
any coercion(convert is explicit and coerce is implicit, for exam, 1.0+2)

Rich comparisons (implemented by methods __eq__() and so on) never use coercion. Three-way comparison
(implemented by __cmp__()) does use coercion under the same conditions as other binary operations use it.

Sunday, April 21, 2013

TIC紧急医疗保险注意事项

违反省医疗计划的费用(比如整体疗法,物理疗法啥的,我也不太懂)不理赔,太扯,因为发生紧急医疗,用什么治疗方式,都是医院定的;

不紧急的医疗不理赔,比较扯,什么是紧急,有多少是紧急,这个由公司界定;

加拿大之外(包括回国)发生的事故不赔偿;

怀孕、流产、堕胎、并发症不理赔;

紧急医疗之后的回访医疗(Follow-up visits) 最高被赔偿$5,000




发生紧急事故,必须24小时通知TIC;手术之前必须通知TIC

如果病人要求回国治疗,因此而发生的一切费用由TIC承担,但是病人一旦被遣返,TIC一般不再承担医疗费用(除非之前经过TIC允许)



Saturday, April 20, 2013

__metaclass__ in python

# __metaclass__ in python
print """to understand __metaclass__, you must know the following true:
Everything is an object.
'class' and 'type' are synonyms.
there is a special class named "type"
a class is an object and it's an instance of its metaclass type
a class's __metaclass__ can be set to metaclass type, which is subtype of type
`print type(int)` will print `type 'type'`
"""
class LonelyBear(object):
    class MetaBear(type): #a subclass of type
        def __new__(meta, name, bases, attrs):
            # do stuff...
            return type.__new__(meta, name, bases, attrs)
    __metaclass__ = MetaBear
print    type(LonelyBear)

__get__ in python

#__get__ in python
import math

class Square(object):
    class Area(object):
        def __get__(self, aBear, clsBear):
            if aBear is None:raise AttributeError
            return aBear.edge_length * aBear.edge_length
           
        def __set__(self, aBear, area):
            if aBear is None:raise AttributeError
            aBear.edge_length = math.sqrt(area)
    area = Area()
   
    def __init__(self,edge_length):
        self.edge_length = edge_length

aSquare = Square(3.0)
print aSquare.area
print Square.__dict__["area"].__get__(aSquare,Square)

aSquare.area = 16.0
print aSquare.edge_length

__dict__ in python

#__dict__ in python

class LonelyBear(object):
    class_attr01 = "default user defined class attr"
    def user_defined_func_or_mtd(self):
        pass

#<type 'dictproxy'>
print type(LonelyBear.__dict__)

#when visit class attr, you can use either class_name.__dict__[attr_name] or class_name.attr_name
if id(LonelyBear.__dict__["class_attr01"]) == id(LonelyBear.class_attr01):
    print "when visit class attr, you can use either class_name.__dict__[attr_name] or class_name.attr_name"

#class_name.__dict__[func_or_mtd_name] is <function user_defined_func_or_mtd at 0x026F4670>
#class_name.func_or_mtd_name is <unbound method LonelyBear.user_defined_func_or_mtd>
func_managed_by_dictproxy = LonelyBear.__dict__["user_defined_func_or_mtd"]
method_managed_by_cls_ns = LonelyBear.user_defined_func_or_mtd
if func_managed_by_dictproxy != method_managed_by_cls_ns:
    print "class_name.__dict__[func_or_mtd_name] is", func_managed_by_dictproxy
    print "class_name.func_or_mtd_name is", method_managed_by_cls_ns

lb = LonelyBear()
an_inst_without_instance_attr = lb.__dict__
#<type 'dict'> {}
print type(an_inst_without_instance_attr), an_inst_without_instance_attr
print """an attr is searched first from instance(inst_name.user_defined_inst_attr, if avaible), then class(cls_name.user_defined_cls_attr),
then the internal(you can use dir(inst_name) to view any possible attr)[note: I am not considering __getattr__ and other hooks]"""

#AttributeError: 'str' object has no attribute '__dict__'
print "some internal type has no __dict__ attr".__dict__

__getattribute__ in python

class shape(object):
    pass
   
class square(shape):
    def __init__(self,side):
        self.side = side
       
    def __getattribute__(self,name):
        if name != "area":return shape.__getattribute__(self,name)
        return self.side*self.side

aSquare = square(5)
print aSquare.side
print aSquare.area

Wednesday, April 17, 2013

__new__ in python

"""
<class '__main__.cchild'> False
True
<class '__main__.cchild'> True
a_base_attr a_child_attr
"""
class cbase(object):
    def __new__(cls):
        #cls is a class, not instance
        print cls,isinstance(cls,cbase)
        #create an instance of sup, and bound cls to it         
        sup=super(cbase, cls)       
        print isinstance(sup,super)
        #now sup know how to create instance of cbase       
        inst_of_cbase = sup.__new__(cls)
        print type(inst_of_cbase),isinstance(inst_of_cbase,cbase)
        #
        return inst_of_cbase
    def __init__(self,base_attr):
        self.base_attr=base_attr

class cchild(cbase):
    def __new__(cls,base_attr,child_attr):
        #before new inst of cchild, new inst of  all of its ancestors   
        return super(cchild, cls).__new__(cchild)
       
    def __init__(self,base_attr,child_attr):
        #explicitly call ancestors's __init__
        cbase.__init__(self,base_attr)
        self.child_attr=child_attr
       
aChild=cchild("a_base_attr","a_child_attr")
print aChild.base_attr,aChild.child_attr

Tuesday, April 16, 2013

[转]博客如何选择广告联盟

一、起付金额越低越好
二、支付方式越方便越好:国内以支持支付宝支付为最优选择,国外以支持paypal支付为最优选择
三、支付周期越短越好:一般而言,广告联盟都是月付,但也有一些是周付,甚至日付的
*四、推荐广告比点击广告更适合博客:因为对于推荐广告而言,文章的内容本身就是广告
*五、注意广告联盟的服务费用/扣量
六、根据自己的网站主题,谨慎地选择一些广告联盟来长久地做:多做做试验,直到找到最适合自己博客的广告联盟为止