2008-06-10

子曰-群而不党

君子和而不同,小人同而不和。
君子矜而不争,群而不党。
君子同而不比,小人比而不同。

-- 《论语》子路篇第十三

柏邦妮是这么解读的:

在我的理解里,这是一种人生要求:

你融和于俗世,但内心葆有不同之处,
你接纳于群体,但不要搞什么小圈子。

世事纷争,莫过于此。受教了。

2008-05-20

向上

汶川地震2008

地震是和平时代的战争,而这张照片,则是中国版的硫磺岛之旗。

军人,白衣天使,消防队员以及志愿者,众人的力量汇聚起来,托起伤者,向前!向上!

有如此的团结齐心协力,更多的灾难又有何惧?

2008,是凤凰涅磐前最后的磨难,中国,必将在灾难的洗礼中浴火重生!

2008-02-26

题牡丹亭 – 冯小青

冷雨敲窗不可听,
挑灯闲看牡丹亭。
人间亦有痴于我,
岂独伤心是小青?

2008-01-02

生成windows远程桌面rdp配置文件

今天研究了一下windows远程桌面客户端,就是system32下面的mstsc.exe。

一向讲究易用性的微软在mstsc.exe中提供了一个将主机地址,用户名、密码等连接所需信息保存到缀名为.rdp的文件中,以便将来快速打开的功能 。

现在我想要做的是,如何自己生成这个.rdp文件,让我自己的程序更方便地调用mstsc.exe?

首先需要做的就是分析.rdp文件的格式。

用文本编辑器打开.rdp文件,可以发现rdp文件的内容以是文本形式的,而且大部分都是明文,只有密码这个字段,明显是经过加密的。

所以,自制rdp文件的任务的关键就是要生成这个密码。

查了一下,mstsc.exe使用的加解密算法分别是CryptProtectData和CryptUnProtectData两个windows API。

知道了这个的话就好办了,直接照着MSDN上CryptProtectData的示例改就行了。

下面给出代码:

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>

void main()
{

    DATA_BLOB DataIn;
    DATA_BLOB DataOut;
    // mstsc.exe中使用的是unicode,所以必须做宽字符转换
    BYTE *pbDataInput =(BYTE *)L"freedom";
    DWORD cbDataInput = wcslen(L"freedom")*sizeof(wchar_t);

    DataIn.pbData = pbDataInput;
    DataIn.cbData = cbDataInput;

    FILE *fp;

    if(CryptProtectData(
        &DataIn,
        L"psw",                                // A description string
                                            // to be included with the
                                            // encrypted data.
        NULL,                               // Optional entropy not used.
        NULL,                               // Reserved.
        NULL,                               // Pass NULL for the
                                            // prompt structure.
        0,
        &DataOut))
    {
        printf("The encryption phase worked.\n");

        fp = fopen("password.txt","w");

        int count=0;
        while ( count <= (int)DataOut.cbData ){
            // 因为一个unsigned int 占32位
            // 转换成成16进制要占两位
            // 所以这里需要用%02
            fprintf(fp,"%02X",DataOut.pbData[count]);
            count++;
        }

        fclose(fp);

    }
    else
    {
        printf("Encryption error using CryptProtectData.\n");
        exit(1);
    }
}

编译时需要指定连接crypt32.lib库,所以一个最简单的编译命令为

cl rdp.cpp crypt32.lib

意外的是,这个程序生成的加密字符串比mstsc.exe生成的要短很多,后面一部分也不一样。但既然是用CryptProtectData加密的,自然也应该能用CryptUnProtectData来解密。实验了一下,果真如此。
回头再想想,微软这么做也是有道理的。因为直接存储CryptProtectData加密过的数据的话,任何人都能使用CryptUnProtectData恢复出明文,加密也就失去了意义。但如果不公开加密算法,那这个rdp文件对于非微软内部的程序员来说,灵活性就变成了0。现在的处理方式既保证了密码的安全性(某种程度上的),也为程序员留下了扩展开发的余地,一个小程序的生命力也由此得到了增强。

见微知著,从一个小东西里面,也可以学到很多。

–EOF–

2008-01-02

修辞

最近有个句式很流行,就是当要比较夸张地表达你对某人的感情的时候,可以这么说:

“我对你的xx,犹如滔滔江水,延绵不绝”

一般这里的xx可以换作鄙视、敬仰等词。

而我伟大的同学老唐,将这句话扩展延伸了一下:

“我对你的xx,犹如滔滔江水,延绵不绝;又如黄河泛滥,一发不可收拾;一江春水向东流,奔流到海不复回;才下眉头,却上心头。”

念完自己笑抽。

可见,修辞是个大学问啊。

–EOF–

2007-12-24

平安夜

吃完晚饭路过超市,遇到蹲在路边摆摊卖棒冰的小贩。

最近哈尔滨的夜晚格外地冷,深吸一口气,细细感觉一下的话,甚至可以感觉到夹杂的煤烟味的空气顺着嗓子一路渗入肺部,吃掉你的体温,进入你的血液。再厚的口罩,再厚的棉服,也难挡这四面八方涌来的寒冷。

我们可以快步前行,赶紧回到温暖的室内开着窗户挥霍暖气,可他们却不得不守在街头,只为挣得明天的生活。

看着他们在寒冷中不住跺脚以驱赶寒冷,忍不住上前买了一支。

今天是基督徒的平安夜,没有上帝的祝福,给自己买支棒冰,也算是给自己的小小的礼物。

Merry Christmas.

记得大四有一晚不愿意睡觉,一个人在黑暗中靠着墙坐在床上。想到,五六年后,当我工作之后,带着一身疲倦回到家,是不是会和现在一样,一个人坐在床头失眠?

如果生命注定孤独,而孤独又是如此痛苦,那生活的意义又在哪里?

在黑暗中不由得感觉自己的意识已经飘远,在高空的某处俯视蜷缩在床头的自己,就在那个瞬间,忽然想起村上的《斯普特尼克恋人》,忽然明白了那种寒彻整个宇宙的孤独。

Lonely Christmas.

当天亮的时候,生活还得继续。毕竟,身后还有殷切期盼的家人。

总会有爱的。

所以,

期待2008。

2007-12-17

记一次root引起的血案

从开始用Linux的那天起,就始终被告知平时不要使用root帐户。但我一直认为,偶是程序员,又不是系统管理员,用root调试程序能方便很多,又何必给自己设这么多限制。

记得上次看到不要用root帐户的理由是:“直到你有一天无意间在根目录下rm -rf *,就会知道这么做的后果” 。当时就感觉这话言过其实了,那有人会那么呆啊。

再说我为人谨慎,一般也是不会误删什么的啦。

后来转用ubuntu,这系统做的更绝,直接把root给禁了。但这对于我也是徒劳,因为每次我装完系统,第一件事就是开启root用户。好在用debian用惯了,平时登陆xwindow不像redhat那样直接用root,但开命令行一般直接就是su -。

今天分到个写安装脚本的任务,用bash。

我也没学过bash编程,但想想也简单,就答应了。边学边写,临近晚饭,差不多快写完了。

就在这时,突然发现某个位置似乎对用户交互不合理,于是改之(事后证明是白改,根本不需要也不能这样)。

改完,测试,快到最后一步的时候报错:

rm : can not delete /dev/xxxx

正在纳闷,这是哪出的错。突然意识到大事不好,ctr+c打断执行,可是为时已晚,根目录下的大部分文件都被删掉了,包括/bin目录。

就这样,一百多G的电影、软件、音乐、还有很多代码,都没了。

写安装脚本的vi窗口还没关,能看到代码,仔细检查,发现问题出在了一个条件判断上

echo -n "请输入xxx安装路径[默认:/usr/local/MyPast] "
read PROG_PATH
if [ "PROG_PATH" = "" ]
then
        PROG_PATH="/usr/local/MyPast"
fi

...

rm -rf $PROG_PATH/*

看出来了么?PROG_PATH前少了个”$”。

测试时选择了默认路径,也就是直接回车,read PROG_PATH后变量PROG_PATH的值为空。

而接下来if中的条件判断由于少了个$,导致比较结果为非真。PROG_PATH=”/usr/local/MyPast”没有执行。

到了下面, rm的参数$PROG_PATH/*被解释为/*

所以 rm -rf $PROG_PATH/*就变成了rm -rf /*

“直到你有一天无意间在根目录下rm -rf *,就会知道这么做的后果” 。

妈的,这回我懂了。

看来这两天真是脚本与维护不宜。前天搞坏了数据库里的数据,今天又干掉了一个系统,郁闷。

2007-12-05

正龙拍虎

上联:正龙拍虎画中取;

下联:关克护虎政绩来;

横批:一塌虎图。

— 网语

2007-11-12

pthread in C++

Linux下的编程一直是C语言的天下,但老是用C感觉写的很乏味。用面向对象方法编程,听着都倍有面子。于是决定先在的这个项目用C++来写。虽然不一定能“以C++的思想”来写C++,少会有C++的样子。

但是问题来了:我需要在程序中动态创建一个线程,而pthread不接受C++类的成员函数作为参数。

原因也很简单,类成员是在类被实例化成为对象后才存在的,即在编译时是不存在的,编译器无法取得函数的确切入口地址,自然无法通过编译。

照这个分析,如果把要调用的类成员函数声明为静态的,pthread_create就可以找到函数的地址了。但这样一来的话,由于类中的静态函数无法调用类的非静态成员。线程函数的功能就受到了很大限制,也就没有比要将其放在类中了。

最容易想到的解决方案就是写个C函数,然后再C函数中调用C++对象的成员函数。

比如类为

class foo(){

    public :
        thread();

}

class *f;

void *bar(void *arg){

    f->thread();       

    return NULL;
}

int  main(){

    .........
    f=new foo();
    
    pthread_create(&tid,&tattr,bar,NULL);

}

显然这种发法太笨了,而且对象只能是全局的。

注意到线程函数bar可以有一个任意类型的指针作为参数,那我们何不将对象通过这个指针将对象变为bar的一个参数,从而让我们的程序好看一些。

class foo(){

    public :
        thread();

}


void *bar(void *args){

    foo *f=(foo *)args;

    f.thread();       

    return NULL;
}

int  main(){

    .........
    foo *f=new foo();
    pthread_create(&tid,&tattr,bar,f);

}

如果把上述两种方法结合起来即对象中的静态函数+通过指针参数传递对象,那又会怎么样呢?

class foo(){

    public :
        int thread();

        static void *wrapper(void *args){
            foo *f=static_cast<foo *>(args);
            f->thread();
            return NULL;
        }

}

int  main(){

    .........
    foo *f=new foo();
    pthread_create(&tid,&tattr,foo::wrapper,&f);

}

现在,强迫症患者,是不是觉得整洁清楚很多了呢?

–Reference–
http://www.osix.net/modules/article/?id=450

–EOF–

2007-10-25

标准释义

标准的好处就是,它提供了很多选择。如果你不喜欢,还可以等明年的。

Andrew S. Tanenbaum. Computer Networks