当前位置:文档之家› 3.漫谈兼容内核之三:关于kernel-win32的文件操作

3.漫谈兼容内核之三:关于kernel-win32的文件操作

3.漫谈兼容内核之三:关于kernel-win32的文件操作
3.漫谈兼容内核之三:关于kernel-win32的文件操作

漫谈兼容内核之三:

Kernel-win32的文件操作

毛德操

上一篇漫谈中分析/介绍了Kernel-win32的对象管理机制。在各种对象类型中,文件显然是最重要、最复杂(就其操作而言)的类型。如果说像“信号量”之类的简单对象还有可能独立地加以实现,那么像文件这样的复杂对象这就不太现实,并且实际上也不合适了。所以,本文的目的就是通过几个典型文件操作的实现介绍kernel-win32是怎样把Windows用于文件操作的系统调用“嫁接”到Linux内核中的有关成分上。

文件的创建

如前文所述,所有的对象都有个Object数据结构,里面有个ObjectClass指针,它指向什么ObjectClass数据结构,这个对象就是什么类型。“文件”就是一种对象类型,它的数据结构是file_objclass:

struct ObjectClass file_objclass = {

"FILE

",

oc_type:

constructor: FileConstructor,

FileReconstructor,

reconstructor:

destructor: FileDestructor,

FilePoll,

poll:

describe:

FileDescribe,

oc_flags: OCF_DONT_NAME_ANON /* names shared from FCTRL class */

};

需要创建一个文件时、或者说需要创建一个类型为文件的对象时,函数_AllocObject()将调用这个结构所提供的函数FileConstructor(),以构造出代表着这个具体对象的数据结构,并且创建并/或打开具体的文件。

另一方面,Object数据结构中还有个指针o_private,指向由上述构造函数生成、代表着具体类别对象的数据结构。对于文件类对象,这个数据结构是WineFile:

/*

* process-access file object definition

* - can't be shared, since they have to have separate attributes for the file

* access

*/

struct WineFile {

struct list_head wf_ctllist; /* file control list next */

WineFileControl *wf_control; /* the file control object */

struct file *wf_file; /* the Linux file */

__u32 wf_access; /* file access mode */

__u32 wf_sharing; /* sharing mode */

__u32 wf_attrs; /* file open attributes */

};

这个数据结构代表着目标文件的一次“打开”。也即一个文件访问上下文。至于没有被打开的文件,则只是存在于磁盘上、或本来就是个外设,在内存中一般不存在相应的数据结构。

注意这里的指针wf_file,这是一个struct file指针。我们知道,struct file就是Linux内核中代表着已打开文件的数据结构,存在于每个进程的“打开文件表”中的就是struct file 指针。由于struct file数据结构所代表的是目标文件的一次打开,所以可以断定WineFile所代表的也是一次打开、即一个上下文(例如可以通过lseek()取得的当前读/写位置),而不是目标文件本身。

显然,对于已经打开的文件,除了代表着文件访问上下文的数据结构以外,还应该有代表着目标文件本身的数据结构。这就是“文件控制类”的对象,其数据结构是WineFileControl:

struct ObjectClass file_control_objclass = {

"FCTRL",

oc_type:

constructor: FileControlConstructor,

FileControlReconstructor,

reconstructor:

destructor: FileControlDestructor,

FileControlPoll,

poll:

FileControlDescribe

describe:

};

文件控制类对象的o_private数据结构则是WineFileControl:

/*

* file-control object definition

* - links together WineFile objects that use the same file

*/

struct WineFileControl {

struct list_head wfc_accessors; /* who's accessing this file */

spinlock_t wfc_lock; /* govern access to list */

Object *wfc_myself; /* my own object */

};

这里的wfc_myself指向其本身的Object数据结构。队列头wfc_accessors用来维持一个“访问者”队列,这是一个WineFile数据结构的队列。WineFile数据结构通过其队列头wf_ctllist挂入这个队列。WineFileControl与WineFile之间是一对多的关系。只要一个文件被打开,内存中就得有一个(并且只有一个)代表着这个文件的WineFileControl数据结构,而WineFile数据结构的数量则取决于对此文件同时共存的上下文个数。在某种意义上,WineFile 是对(Linux的)struct file数据结构的包装和扩充,而WineFileControl是对struct dentry数据结构的的补充。但是,应该在WineFileControl中加以补充的Windows文件所独有(有别于Linux文件属性)的属性有很多,而这里却什么也没有。所以目前这个数据结构的定义只是提供了一个空的骨架,还有待充实。

还有值得一提的是,打开目标文件以后的struct file指针wf_file保存在WineFile数据结构中,而不是保存在Linux进程(线程)的打开文件表中。这意味着设计者的意图是另起炉灶、完全由自己来管理Windows进程所打开的文件,而与Linux的有关机制分道扬镳。可是这是有可能带来问题的。举个例子来说明这一点:假定一个Windows进程在运行中发生了问题,或者被别的进程kill,从而执行了do_exit()。在退出运行的过程中,do_exit()会扫描该进程的打开文件表,根据表中的struct file指针关闭所有已打开文件、并释放资源。可是现在Windows进程的struct file指针不在打开文件表中,因而就享受不到这个待遇。设计者显然意识到这一点,所以在有关的内核代码上打了补丁,让它调用一个外挂函数(见前一篇漫谈)。然而,我们却看到有关的外挂函数尚未实现。对于诸如此类的问题,是尽量利用Linux 内核原有的代码较好?还是另起炉灶较好?应该说是各有利弊,具体的情况需要具体分析,总之是值得推敲的。

介绍了这些背景以后,我们可以阅读kernel-win32所实现的代码了。这里看三个系统调用的代码,分别是CreateFileA()、ReadFile()、和CloseHandle()。了解了这三种操作,对于kernel-win32文件操作的实现就知道了个大概,再进一步阅读其它有关的代码也就不难了。这三个系统调用的函数名与一般Windows文献中所见有所不同,但是这没有什么关系,因为这些函数是内核中不向外界开放(导出)的函数,叫什么都可以。

先看CreateFileA(),这个函数根据给定的路径名打开一个文件,如果这个文件尚不存在就加以创建、并且打开。这跟Linux的sys_open()基本上是一致的,只是函数名sys_open()突出了“打开”而CreateFileA()突出了“创建”。不过,除CreateFile()外,Windows另有一个系统调用OpenFile(),这很容易让人误以为前者是只创建不打开,而后者是只打开不创建。

还有,函数名CreateFileA()中的“A”表示ASCII,意思是所涉及的字符串(例如文件名)是8位ASCII码。与之相对的是“W”,表示16位“宽”字符,或Unicode。

下面就来看代码。

/*

* open a file object, maybe creating if non-existent

*/

int CreateFileA(struct WineThread *thread, struct WiocCreateFileA *args)

{

HANDLE

hFile;

*obj;

Object

/* must have a name... */

(!args->lpFilename)

if

-EINV AL;

return

/* ...but create the object _without_ a name and attach one later

* (need a separate file-access object for each CreateFileA

*/

obj

= CreateObject(thread, &file_objclass, NULL, args, &hFile);

(IS_ERR(obj))

if

PTR_ERR(obj);

return

ktrace("*** [%d] CreateFileA(%p) = %p\n",current->pid,obj,hFile);

objput(obj);

hFile;

return

(int)

} /* end CreateFileA() */

Kernel-win32所实现的系统调用通过数据结构传递参数,这是与Windows不同、而带有Linux风格的做法;原因就是Kernel-win32通过Linux系统调用来“搭载”实现Windows 系统调用。对于CreateFileA(),这个数据结构是struct WiocCreateFileA。

struct WiocCreateFileA {

lpFilename;

__pad__

LPCSTR

dwDesiredAccess;

__pad__

DWORD

dwShareMode;

__pad__

DWORD

LPSECURITY_ATTRIBUTES __pad__ lpSecurityAttributes;

__pad__ dwCreationDisposition;

DWORD

__pad__ dwFlagsAndAttributes;

DWORD

HANDLE __pad__ hTemplateFile;

};

可见与open()的参数有相当大的不同,这里限于篇幅不作介绍了,读者可参阅有关的Windows文献和资料。

程序的主体就是CreateObject()。如我在上一篇漫谈中所示,这个函数先调用_AllocObject()创建具体的Object数据结构(并完成实际目标的创建和/或打开操作),然后把指向该数据结构的指针安装在所属进程的“打开对象表”中,并返回实质上是数组下标的Handle。而_AllocObject()则进一步细化,通过由file_objclass数据结构所提供的函数指针调用FileConstructor(),这才是实质性的操作。

[CreateFileA() > CreateObject() > _AllocObject() > FileConstructor()]

/*

* construct a file access object (allocate its private data)

* - called by CreateObject if the file does not already exists

* - called with the object class lock held

*/

static int FileConstructor(Object *obj, void *data)

{

struct WiocCreateFileA *args = data;

*wf;

struct

WineFile

*fco;

Object

struct

int err, flags, mode;

ktrace("FileConstructor(%p)\n",obj);

/* construct the file information record */

wf = (struct WineFile *) kmalloc(sizeof(struct WineFile),GFP_KERNEL);

(!wf)

if

-ENOMEM;

return

obj->o_private = wf;

wf->wf_access = args->dwDesiredAccess;

=

args->dwShareMode;

wf->wf_sharing

wf->wf_attrs = args->dwFlagsAndAttributes;

/* gain access to the file control object */

=

AllocObject(&file_control_objclass, args->lpFilename, data);

fco

if (IS_ERR(fco)) {

PTR_ERR(fco);

=

err

cleanup_priv;

goto

}

wf->wf_control = fco->o_private;

spin_lock(&wf->wf_control->wfc_lock);

/* make use of the name stored in the file control object */

obj->o_https://www.doczj.com/doc/0d14765967.html, = fco->o_https://www.doczj.com/doc/0d14765967.html,;

/* check that we can share access */

err

FileCheckSharing(args, wf->wf_control);

=

(err<0)

if

cleanup_fco;

goto

/* determine Linux file open parameters */

switch (args->dwCreationDisposition) {

case CREATE_NEW: flags = O_CREAT | O_EXCL; break;

case CREATE_ALWAYS: flags = O_CREAT | O_TRUNC; break;

case OPEN_ALWAYS: flags = O_CREAT; break;

case TRUNCATE_EXISTING: flags = O_TRUNC; break;

case OPEN_EXISTING: flags = 0; break;

default:

err = -EINV AL;

goto

cleanup_fco;

}

switch (args->dwDesiredAccess & (GENERIC_READ|GENERIC_WRITE)) { case 0: break;

case GENERIC_READ: flags |= O_RDONLY; break;

case GENERIC_WRITE: flags |= O_WRONLY; break;

case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;

}

mode = (args->dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY)? 0444 : 0666;

/* open the Linux file */

=

filp_open(obj->o_https://www.doczj.com/doc/0d14765967.html,, flags, mode);

wf->wf_file

if (IS_ERR(wf->wf_file)) {

PTR_ERR(wf->wf_file);

err

=

cleanup_fco;

goto

}

/* don't permit a directory to be opened */

(S_ISDIR(wf->wf_file->f_dentry->d_inode->i_mode)) {

if

=

-EACCES;

err

cleanup_file;

goto

}

list_add(&wf->wf_ctllist, &wf->wf_control->wfc_accessors);

spin_unlock(&wf->wf_control->wfc_lock);

kdebug("FileConstructor: f_count=%d i_count=%d i_wc=%d\n",

atomic_read(&wf->wf_file->f_count),

atomic_read(&wf->wf_file->f_dentry->d_inode->i_count),

atomic_read(&wf->wf_file->f_dentry->d_inode->i_writecount));

0;

return

/* clean up on error */

cleanup_file:

fput(wf->wf_file);

cleanup_fco:

obj->o_https://www.doczj.com/doc/0d14765967.html, = NULL;

spin_unlock(&wf->wf_control->wfc_lock);

objput(wf->wf_control->wfc_myself);

cleanup_priv:

WineFile));

poison(wf,sizeof(struct

kfree(wf);

err;

return

} /* end FileConstructor() */

简而言之,这个函数的操作主要有这么一些:

1.通过kmalloc()分配一块空间用于WineFile数据结构。

2.将调用参数纪录在WineFile数据结构中。

3.通过AllocObject()找到或创建代表着目标文件的“文件控制”对象。

4.通过FileCheckSharing()检查是否允许调用参数所要求的访问模式。

5.将调用参数所要求的操作模式(CREATE_NEW、CREATE_ALWAYS、OPEN_ALWAYS

等等)和访问模式(GENERIC_READ、GENERIC_WRITE等)换算成Linux的相应标志位。

6.调用Linux内核函数filp_open(),以打开目标文件,并将已打开文件的struct file结构指

针填写在WineFile数据结构中。

7.通过list_add()将前面创建的WineFile数据结构挂入相应WineFileControl数据结构的

wfc_accessors队列中。

上面AllocObject()的主体就是对_AllocObject()的调用。而_AllocObject(),则先试图根据类型(在这里是file_control_objclass)和对象名找到目标对象,找不到才加以创建。所以“文件控制”对象与“打开文件”对象之间是一对多的关系。如果目标文件尚未被打开,因此需要创建“文件控制”对象的话,就会调用他的构建函数FileControlConstructor():

[CreateFileA() > CreateObject() > AllocObject() > _AllocObject() > FileControlConstructor()]

/*

* construct a file control object (allocate its private data)

* - called by AllocObject if the file does not already exists

* - called with the object class lock held

*/

static int FileControlConstructor(Object *obj, void *data)

{

*wfc;

WineFileControl

struct

ktrace("FileControlConstructor(%p)\n",obj);

/* construct the file information record */

wfc = (struct WineFileControl *) kmalloc(sizeof(struct WineFileControl),GFP_KERNEL);

(!wfc)

if

-ENOMEM;

return

obj->o_private = wfc;

INIT_LIST_HEAD(&wfc->wfc_accessors);

spin_lock_init(&wfc->wfc_lock);

wfc->wfc_myself

obj;

=

0;

return

} /* end FileControlConstructor() */

显然,这个函数毫无特殊之处,而且比前面的FileConstructor()简单多了。这当然是因为许多功能和特性尚未实现的缘故,而并不是本来就应该这么简单。

回到FileConstructor()的代码中,还有FileCheckSharing()是值得一提的。这个函数根据CreateFileA()的调用参数dwDesiredAccess和dwShareMode检查所要求的访问模式(例如GENERIC_READ和GENERIC_WRITE)和共享模式(例如FILE_SHARE_READ)是否与目标文件已有的各个“打开”相容。具体地说,就是扫描目标文件的WineFileControl结构中的wfc_accessors队列,与队列中各个WineFile结构中记载的访问模式和共享模式进行比较,以确定是否相容。

创建并/或打开了文件以后,就可以对文件进行各种操作了,最重要的当然是读/写。所以我们就来看看读文件操作的实现。在Windows上,读文件是通过系统调用NtReadFile()进行的。在Kernel_win32的代码中,这个系统调用在内核中的实现就是ReadFile()。同样,调用参数都包装在一个数据结构中:

struct WiocReadFile {

HANDLE __pad__ hFile;

LPVOID __pad__ lpBuffer;

__pad__ nNumberOfBytesToRead;

DWORD

LPDWORD __pad__ lpNumberOfBytesRead;

__pad__ lpOverlapped;

LPOVERLAPPED

};

前面三个参数的用途是不言自明的。参数lpNumberOfBytesRead则是个指针,用来返回实际读出的字节数。显然这与Linux的sys_read()不同,因为后者是把它作为函数值返回的。另一个参数lpOverlapped也是个指针,用于异步的读文件操作。所谓异步,是指调用者并不(睡眠)等待操作的完成,而是把访问的要求交给内核以后就先返回干别的事,内核在完成操作以后再予以“回叫(callback)”。但是Kernel-win32尚未实现此项功能。

下面我们看ReadFile()的代码。

int ReadFile(struct WineThread *thread, struct WiocReadFile *args)

{

struct

*wf;

WineFile

struct file *file;

Object *obj = NULL;

ret;

int

kdebug("ReadFile(%p,%p)\n",thread,args->hFile);

0;

=

ret

put_user(ret,args->lpNumberOfBytesRead);

=

ret

(ret<0)

if

cleanup_nobj;

goto

obj

GetObject(thread,args->hFile,&file_objclass);

=

(IS_ERR(obj))

if

PTR_ERR(obj);

return

wf = obj->o_private;

file = wf->wf_file;

ktrace("*** [%d] ReadFile(%p,%p,%u)\n",

current->pid,obj,

args->lpBuffer,

args->nNumberOfBytesToRead

);

/* check the file can actually be read */

ret = -EACCES;

if (!(wf->wf_access & GENERIC_READ))

cleanup;

goto

ret = -EBADF;

if (!(file->f_mode & FMODE_READ))

cleanup;

goto

ret = -EINV AL;

|| !file->f_op->read)

(!file->f_op

if

cleanup;

goto

/* check that the area isn't mandatorally locked */

ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,

args->nNumberOfBytesToRead);

file,

file->f_pos,

(ret<0)

if

cleanup;

goto

/* try and read */

ret

= file->f_op->read(file, args->lpBuffer, args->nNumberOfBytesToRead, &file->f_pos);

(ret<0)

if

cleanup;

goto

ktrace("*** [%d] ReadFile(%p) read %d bytes\n",current->pid,obj,ret);

put_user(ret,args->lpNumberOfBytesRead);

0;

ret

=

cleanup:

objput(obj);

cleanup_nobj:

ktrace("*** [%d] ReadFile(%p) = %d\n",current->pid,obj,ret);

ret;

return

} /* end ReadFile() */

这个函数的逻辑是很简单的:先根据Handle通过当前线程的打开对象表找到目标对象,并进一步找到其WieFile数据结构,指向目标文件的struct file结构的指针就保存在WieFile 数据结构中;然后在Wine和Linux文件系统两个层面上检查访问权限;最后通过Linux文件系统实施具体的读出。这个过程清楚地表明Kernel-win32是怎样把Windows的文件操作嫁接到Linux文件操作上的。读操作如此,写操作也是大同小异。

再看“关闭文件”的操作。Windows并没有专门针对文件的“关闭文件”操作,而只有“关闭Handle”操作,因为文件只是“对象”中的一种。

int CloseHandle(struct WineThread *thread, struct WiocCloseHandle *args)

{

WineProcess

*process;

struct

Object **ppobj, **epobj, *obj;

last;

int

ktrace("*** [%d] CloseHandle(%p,%p)\n",

current->pid,thread,args->hObject);

/* validate the handle */

if (args->hObject

args->hObject>=MAXHANDLE ||

((__u32)args->hObject & (sizeof(Object*)-1))

)

return

-EINV AL;

GetWineProcess(thread);

process

=

write_lock(&process->wp_lock);

ppobj = (Object**)

((char*)&process->wp_handles + (__u32)args->hObject – sizeof(Object*));

*ppobj;

obj

=

*ppobj = NULL;

/* see if this was the last attachment from this "process" */

=

&process->wp_handles[MAXHANDLES];

epobj

1;

=

last

if (obj && obj->o_class->detach) {

for (ppobj=process->wp_handles; ppobj

{

(*ppobj==obj)

if

last = 0; /* yes */

break;

}

}

}

write_unlock(&process->wp_lock);

(!obj)

if

return

-EBADF;

if (last && obj->o_class->detach)

obj->o_class->detach(obj,process); /* last attachment gone */

objput(obj);

return

0;

} /* end CloseHandle() */

开始时在所属进程的打开对象表中搜索,根据Handle找到目标对象的过程跟前面ReadFile()中调用的GetObject()基本相同,不同的是这里要把打开对象表中的相应表项写成NULL,以断开跟目标对象的连系。接下去的意图很明显,就是检查这是否当前进程对目标对象的最后一个Handle,即是否对目标对象的最后一个打开,如果是就调用该类对象的detach操作(注意代码中的注释“yes”意思反了)。可是,看一下文件类对象的数据结构file_objclass,就可以发现它并没有提供detach函数,所以实际上并不会执行。看来,在kernel-win32的设计中,关闭文件类对象时并不需要detach操作。然而在关闭对象时总得对目标对象做点什么啊,否则其数据结构所占的空间何时才能释放?这就是下面objput()要做的事。

[CloseHandle() > objput()]

/*

* decrement an object's usage count

* - when usage count reaches zero, the object is destroyed

* - uses the class's rwlock to govern access to the count

*/

void objput(Object *obj)

{

ktrace("objput(%p)\n",obj);

if (!obj) return;

#ifdef OBJECT_MAGIC

(obj->o_magic!=OBJECT_MAGIC)

if

magic\n");

object

panic("bad

#endif

write_lock(&obj->o_class->oc_lock);

if

(!atomic_dec_and_test(&obj->o_count))

still_in_use;

goto

#ifdef OBJECT_MAGIC

obj->o_magic = 0x01010101;

#endif

list_del(&obj->o_objlist);

obj->o_class->destructor(obj);

write_unlock(&obj->o_class->oc_lock);

/* quick insanity check */

if (waitqueue_active(&obj->o_wait)) {

"wineserver:"

printk(KERN_ALERT

" object being deleted is still being waited upon\n");

return;

}

putname(obj->o_https://www.doczj.com/doc/0d14765967.html,);

if

(obj->o_https://www.doczj.com/doc/0d14765967.html,)

poison(obj,sizeof(Object));

kfree(obj);

return;

still_in_use:

write_unlock(&obj->o_class->oc_lock);

} /* end objput() */

首先通过atomic_dec_and_test()递减目标对象的引用计数、并测试其结果。如果尚未达到0,就说明目标对象还有用户,所以就不需要有进一步的处理。否则,要是计数达到了0,那就要把它从对象队列中删除,并调用该类对象的destructor函数。文件类对象的destructor 函数是FileDestructor()。

[CloseHandle() > objput() > FileDestructor()]

/*

* destroy a file (discard its private data)

*/

static void FileDestructor(Object *obj)

{

struct WineFile *wf = obj->o_private;

kdebug("FileDestructor: f_count=%d i_count=%d i_wc=%d\n",

atomic_read(&wf->wf_file->f_count),

atomic_read(&wf->wf_file->f_dentry->d_inode->i_count),

atomic_read(&wf->wf_file->f_dentry->d_inode->i_writecount)

);

ktrace("FileDestructor(%p)\n",obj);

/* discard my association with the Linux file */

fput(wf->wf_file);

/* unlink from the controlling object */

list_del(&wf->wf_ctllist);

obj->o_https://www.doczj.com/doc/0d14765967.html, = NULL;

objput(wf->wf_control->wfc_myself);

poison(obj->o_private,sizeof(struct

WineFile));

kfree(obj->o_private);

} /* end FileDestructor() */

先通过fput()切断与Linux文件系统中目标文件struct file结构的连系,然后将WineFile 数据结构从目标文件控制对象的队列中删除,再对目标文件控制对象也实施objput(),最后释放WineFile数据结构。在释放前还调用了一个函数poison(),那只是将WineFile数据结构中的内容破坏掉。注意前面objput()中也调用了poison()和kfree(),那是释放目标对象的Object 数据结构,而这里释放的是与之配套的WineFile数据结构。

从上述创建文件、读文件、和关闭文件这三个文件操作的代码中,我们可以体会到:“内核差异内核补”、把Windows的文件操作嫁接到Linux文件操作上面、其逻辑和思路是多么简单明了,这与Wine试图在核外解决问题的做法形成了鲜明的对比。虽然本文没有涉及写文件操作的代码,但是读者想必明白那是大同小异。

更重要的是,与Wine相比,逻辑上和操作上的这种简化和优化必将大大提高文件操作的效率。

但是,另一方面,我们也应看到,Kernel-win32只是朝正确的方向走了一小步,迄今所实现的只是系统调用界面的一个很粗糙、很不完整的骨架,离实用还相距甚远,而且许多具体的设计和实现也值得推敲。

在CreateFileA()的过程中,我们在前面FileConstructor()的代码中可以看到调用参数之一lpSecurityAttributes根本就没有被引用;另一个参数dwFlagsAndAttributes虽然被引用了,但只是检查了其中的“只读”标志位。然而这两个调用参数恰恰是很重要的。例如lpSecurityAttributes是个指针,应该指向一个SECURITY_ATTRIBUTES数据结构,Windows DDK中有这个数据结构的定义:

typedef struct _SECURITY_ATTRIBUTES {

DWORD nLength;

LPVOID lpSecurityDescriptor;

BOOL bInheritHandle;

} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

可见,这个数据结构中不光有关于(所创建)目标文件安全特性的描述,还规定了这个文件本次打开后的上下文是否可遗传。尽管许多应用程序在调用CreateFileA()时会对此给出一个NULL指针,表示采用默认的行为特征,但是有些应用程序却会利用这个参数。忽略这个参数无疑有可能会使那样的应用程序产生一些令人莫名其妙的结果。

再看dwFlagsAndAttributes,这个参数也绝不只是一个FILE_ATTRIBUTE_READONLY 标志位那么简单。例如其中有个标志位是FILE_FLAG_DELETE_ON_CLOSE,表示在关闭这个文件时应将其删除。再例如FILE_ATTRIBUTE_COMPRESSED也是个标志位,其作用不言自明。显然,Kernel-win32只考虑了其中的FILE_ATTRIBUTE_READONLY,而留下了大量其它的标志位未作处理,甚至在数据结构中也没有为保存这些成分留下空间。实际上,实现那些标志位的工作量可能远远超过Kernel-win32迄今已有的实现。

此外,ReadFile()的参数lpOverlapped也没有被用到,这是用来实现异步操作的。Linux 内核也支持异步文件操作,但是显然这里还没有考虑把它嫁接过去。

还有特别值得一提的是已打开对象的遗传问题。显然Kernel-win32对此还没有考虑,因为否则在Object结构中(或者别的什么数据结构中)总得有个地方来保存有关的信息。

最后还要提一下跨进程的Handle复制。我在以前的漫谈中也曾讲到,只有在内核中才能有效率地实现这个功能,但是我们并没有看到Kernel-win32在做这件事的迹象。

不过,尽管差距还很大,由于Kernel-win32毕竟是在内核中弥补这些差距,所以原则上并不存在大的障碍,只是还没有来得及做、或者是否准备做的问题。

实际上,这正是所谓“20/80原理”的一个例证。就文件操作而言,有了打开/创建、读、写、移动读写位置这些基本功能,许多应用程序就可以运行了。实现这些基本功能的工作量和复杂性可能只是20%,而受惠的应用软件可能是80%。但是要让剩下来的那20%也能运行起来,所要求的工作量和复杂性则可能有80%。所以前面那20%的工作当然应该优先。然而,想要达到“高度兼容”的目的,是绝不能置那20%于不顾的。就像艺术表现的真实性往往在于细节一样,兼容程度的高低也往往深受细节的影响。而且,有些“细节”考虑甚至可能会导致推翻原来的设计方案。例如关于跨进程复制Handle的考虑、关于遗传方式的考虑、就使得Wine实际上不可能达到高度兼容,至少是不可能达到比较有效率的高度兼容(更何况还有设备驱动的问题)。而Kernel-win32,说是对Wine的优化,实质上就是推翻了Wine原来的设计方案。好在Kernel-win32的工作已经做到了内核中,从大的方面来说,总体的设计方案已经不太会因为某些细节不好实现而被推翻了,但是一些具体的设计、具体的实现、则仍是可以推敲和改变的。

对于兼容内核,Kernel-win32要实现的相当于它的一个子集,即其系统调用界面。因此兼容内核理应从Kernel-win32吸取营养,甚至直接“拿来”。不过由于Kernel-win32还很很粗糙、很不完整,一些具体的设计和实现也值得推敲,所以能直接“拿来”的大概不多。倒是它对于各种成分的轻重缓急和实现次序方面的考虑,还是值得、也应该借鉴的。

Linux常用命令

Linux常用命令1、查看当前工作路径:pwd 示例: 2、列出目录中的内容:ls 格式: ls [选项] [目录名称] 常用选项和参数: -l :显示文件和目录的详细信息。 -d : 显示目录名称而非其内容。 -S : 按文件和目录的大小排序。 -t : 按文件和目录的更改时间排序。 -a :显示目录中的文件和文件夹,包括隐藏文件。 示例: ?查看当前目录下的文件和文件夹详细信息。 3、切换工作目录:cd 格式: cd [目录名称] (直接执行cd命令,进入个人主目录。)示例:

4、创建目录:mkdir 格式: mkdir [选项] [目录名称] 常用选项和参数: -p :确保目录名称存在,如果目录不存在的就新创建一个。 示例: ?在/test/test1目录下创建一个名称为“test2”的目录。(/test目录下还没有创建test1,添加-p参数一次性创建) 5、创建文件:touch 格式: touch [文件名称] 示例: ?创建一个名称为“linux”的文件。 6、删除文件或目录:rm 格式: rm [选项] [文件或目录名称] 常用选项和参数: -f :强制删除文件或目录。 -r :递归处理,将指定目录下的所有文件及子目录一并处理。 示例: ?删除一个名称为“/test1”的目录。

7、移动或更名现有的文件或目录:mv 格式: mv[选项][源文件或目录][目标文件或目录] 常用选项和参数: -f :若目标文件或目录与现有的文件或目录重复,则直接覆盖现有的文件或目录。 示例: ?将/etc/hosts文件移动到/home目录。 8、复制文件或目录:cp 格式: cp[选项][源文件或目录][目标文件或目录] 常用选项和参数: -a :此参数的效果和同时指定"-dpR"参数相同。 -d :当复制符号连接时,把目标文件或目录也建立为符号连接,并指向与源文件或目录连接的原始文件或目录。 -p :保留源文件或目录的属性。 -R :递归处理,将指定目录下的所有文件与子目录一并处理。 示例: ?复制/var/log/messages文件到/home目录。 cp /var/log/messages /home ?复制/var/log文件夹到/home目录。 cp -a /var/log /home

linux导出文件到本地

测试环境是linux服务器,所以经常会传输文件到服务器,或者从服务器下载文件。如果服务器安装了FTP,那么直接用FTP软件来下载就可以了,如果没有安装,那么就要用DOS命令来解决了,以下以下载文件到windows本机为例,简单说下整个过程。 一、服务器文件打包 注:因为我经常要下载很多文件,而且文件也比较大,所以需要打包,如果你只是下载单个文件或文件大小不大,那就省略此步吧。 1、本机上打开cmd窗口,用telnet命令登录服务器,具体命令用法是:telnet 服务器IP地址,如要登录的服务器地址是10.10.10.10 ,那么按下图输入 2、回车,输入用户名和密码登录服务器 3、进入要下载的文件或文件夹所在的目录 4、使用tar命令对文件或文件夹打包。 5. 语法:tar命令 一、功能说明:用来建立,还原备份文件的工具程序,它可以加入,解开备份文件内的文件 二、参数: -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个。下面的参数是根据需要在压缩或解压档案时可选的。 -z:有gzip属性的

-j:有bz2属性的 -Z:有compress属性的 -v:显示所有过程 -O:将文件解开到标准输出 下面的参数-f是必须的 -f: 使用档案名字,切记,这个参数是最后一个参数,后面只能接档案名。 三、举例说明: tar -cf all.tar *.jpg 这条命令是将所有.jpg的文件打成一个名为all.tar的包。-c是表示产生新的包,-f指定包的文件名。 tar -rf all.tar *.gif 这条命令是将所有.gif的文件增加到all.tar的包里面去。-r是表示增加文件的意思。tar -uf all.tar logo.gif 这条命令是更新原来tar包all.tar中logo.gif文件,-u是表示更新文件的意思。 tar -tf all.tar 这条命令是列出all.tar包中所有文件,-t是列出文件的意思 tar -xf all.tar 这条命令是解出all.tar包中所有文件,-t是解开的意思 压缩 tar –cvf jpg.tar *.jpg //将目录里所有jpg文件打包成jpg.tar tar –czf jpg.tar.gz *.jpg //将目录里所有jpg文件打包成jpg.tar后,并且将其用gzip 压缩,生成一个gzip压缩过的包,命名为jpg.tar.gz tar –cjf jpg.tar.bz2 *.jpg //将目录里所有jpg文件打包成jpg.tar后,并且将其用bzip2压缩,生成一个bzip2压缩过的包,命名为jpg.tar.bz2 tar –cZf jpg.tar.Z *.jpg //将目录里所有jpg文件打包成jpg.tar后,并且将其用compress压缩,生成一个umcompress压缩过的包,命名为jpg.tar.Z rar a jpg.rar *.jpg //rar格式的压缩,需要先下载rar for linux zip jpg.zip *.jpg //zip格式的压缩,需要先下载zip for linux 解压 tar –xvf file.tar //解压 tar包 tar -xzvf file.tar.gz //解压tar.gz tar -xjvf file.tar.bz2 //解压 tar.bz2 tar –xZvf file.tar.Z //解压tar.Z

16位、32位和64位操作系统的区别

16位、32位和64位操作系统的区别 我们这里先讲32bit与64bit系统的区别: 大体上来讲,64位的系统比32位的系统计算处理能力更精确更加强.-----------用计算器计算时有64位数字可以显示出来,而我们普通的32位系统最精确只能显示32个数字,这是一个小的区别.---------最主要的区别就是64位的XP需要你的CPU也是64位的.64位的技术比32位先进,但由于配套的相关的软硬件技术尚未成熟,很多情况下64位系统只能运行32位软件,现在的64位系统就象是一部跑车由于没有公路只能在农田里跑一样. --32位、64位代表的是使用cpu位数(64,32) 有时候人们怀疑一个系统的底层结构能否保证这个系统在被使用时达到安全而高效,64位版本的Windows 在这方面就比较完美。Windows XP和Windows Server 2003都是运行64位硬件的64位版本操作系统。64位Windows操作系统运行64位代码,同时通过使用WoW64 (Windows on Windows 64)也能运行32位代码。 你看,这并不是什么大问题,毕竟,32位版本的不同Windows操作系统都用来同时运行32位和16位代码。(技术上说,并不是同时运行,相关解释在以后的技巧中会展示给大家) 32位版本的Windows在如何允许32为和16位代码并肩运行方面有着很复杂的机制。然而,这个系统被设计成无论你是系统管理员还是临时用户,你都不需要知道这些机制如何运行。 但是64位版本的Windows就不同了。从一个用户的立场上看,64位应用程序和32位应用程序简单地同时运行,没有什么特殊的。但是对于一个管理员(和帮助桌面用户的人员)来说,这其中就有很大不同了:32位代码与64位代码相隔离。这个隔离是如此重要以至于64位版本的Windows有两个注册表,一个是针对64位,一个是针对32位。 尽管64位版本的Windows XP和Windows Server 2003看起来在操作时候和它们32位的版本几乎同样的,但是在表象之下其实是有很大不同的。如果你在64位版本的Windows下按照32位版本一样来执行某些程序,你可能引起一些麻烦。 --------- 16、32、64位是指cpu可寻址的长度。例如32位计算机,CPU可寻址的范围是0到2的32次方减1,也就是说内存最大可达2的32次方个字节,也就是4GB.

设备驱动加到Linux内核中

7.2.3 设备驱动加到Linux内核中 设备驱动程序编写完后将该驱动程序加到内核中。这需要修改Linux 的源代码,然后重新编译内核。 ①将设备驱动程序文件(比如mydriver.c)复制到/Linux/drivers/char目录下。该目录保存了Linux下字符设备的设备驱动程序。修改该目录下mem.c 文件,在int chr_dev_init()函数中增加如下代码: #ifdef CONFIG_MYDRIVER device_init(); #endif 其中CONFIG_MYDRIVER是在配置Linux内核时赋值。 ②在/linux/drivers/char目录下Makefile中增加如下代码: ifeq ($(CONFIG_MYDRIVER),y) L_OBJ + = mydriver.o endif 如果在配置Linux内核时选择了支持新定义的设备,则在编译内核时会编译mydriver.c生成mydriver.o文件。 ③修改/linux/drivers/char目录下config.in文件,在 comment Character devices 语句下面加上 bool suppot for mydriver CONFIG_MYDRIVER 这样,若编译内核,运行make config,make menuconfig或make xconfig,那么在配置字符设备时就会有选项: Support for mydriver 当选中这个设备时,设备驱动就加到了内核中了。 重新编译内核,在shell中将当前目录cd 到Linux目录下,然后执行以下代码: # make menuconfig # make dep # make 在配置选项时要注意选择支持用户添加的设备。这样得到的内核就包含用户的设备驱动程序。 Linux通过设备文件来提供应用程序和设备驱动的接口,应用程序通过标准的文件操作函数来打开、关闭、读取和控制设备。查看Linux文件系统下的/proc/devices,可以看到当前的设备信息。如果设备驱动程序已被成功加进,这里应该由该设备对应的项。/proc/interrupts纪录了当时中断情况,可以用来查看中断申请是否正常;对于DMA和I/O口的使用,在/proc下都有相应的文件进行记录;还可以在设备驱动程序中申请在/proc 文件系统下创建一个文件,该文件用来存放设备相关信息。这样通过查看该文件就可以了解设备的使用情况。总之,/proc文件系统为用户提供了查

linux查看文件大小命令

linux查看文件大小命令 linux系统不像windows系统,查看文件可以随时点击右键,linux中碳钢命令来查看文件大小,下面由小编为大家整理了linux查看文件命令的相关知识,希望对大家有帮助! linux查看文件命令详解 du [-abcDhHklmsSx] [-L <符号连接>][-X <文件>][--block-size][--exclude=<目录或文件>] [--max-depth=<目录层数>][--help][--version][目录或文件] 常用参数: -a或-all 为每个指定文件显示磁盘使用情况,或者为目录中每个文件显示各自磁盘使用情况。 -b或-bytes 显示目录或文件大小时,以byte为单位。 -c或–total 除了显示目录或文件的大小外,同时也

显示所有目录或文件的总和。 -D或–dereference-args 显示指定符号连接的源文件大小。 -h或–human-readable 以K,M,G为单位,提高信息的可读性。 -H或–si 与-h参数相同,但是K,M,G是以1000为换算单位,而不是以1024为换算单位。 -k或–kilobytes 以1024 bytes为单位。 -l或–count-links 重复计算硬件连接的文件。 -L<符号连接>或–dereference<符号连接> 显示选项中所指定符号连接的源文件大小。 -m或–megabytes 以1MB为单位。 -s或–summarize 仅显示总计,即当前目录的大小。

Linux内核—文件系统模块的设计和开发

Linux内核—文件系统模块的设计和开发 郑小辉 摘要:目前,Linux技术已经成为IT技术发展的热点,投身于Linux技术研究的社区、研究机构和软件企业越来越多,支持Linux的软件、硬件制造商和解决方案提供商也迅速增加,Linux在信息化建设中的应用范围也越来越广,Linux产业链已初步形成,并正在得到持续的完善。随着整个Linux产业的发展,Linux技术也处在快速的发展过程中,形成了若干技术热点。 本文介绍了Linux的发展和特点,以及与其他文件系统的区别。文中主要是对Linux2.4.0内核文件系统源代码的分析,并参考其文件格式设计一个简洁的文件系统。源代码的分析主要介绍了VFS文件系统的结构,Linux自己的Ext2文件系统结构,以及文件系统中的主要函数操作。 在设计的简洁文件系统中,通过调用一些系统函数实现了用户的登录、浏览目录、创建目录、更改目录、创建文件以及退出系统功能。 关键字:Linux 源代码分析文件系统Ext2 Linux内核

Linux kernel -Design and development for the File System Module Zheng xiaohui Abstract: Currently, Linux IT technology has become a hot development technology. Participating in Linux technology research communities, research institutes and software enterprises are in support of Linux more and more, software and hardware manufacturers and solution providers have increased rapidly, In the development of the information industry the Linux application is also increasing, Linux industry chain has taken shape, and is sustained improvemently. With the entire industry in the development of Linux, and Linux is also at the rapid development process, formed a number of technical points. This paper presents the development of Linux and features, and with other file system differences. The main text of the document is Linux2.4.0 system kernel source code analysis, and I reference its file format to design a simple file system. The analysis of the source code mainly on the VFS file system structure, Linux Ext2 its own file system structures, file systems and the main function operation. In the design of the file simple system, some system function is used to achieve function such as: the user's login, browse catalogs, create directories, Change directory, create documents and withdraw from the system function and etc. Key words: Linux, the source code, file system, Ext2, Linux kernel

Linux中C语言open函数打开或创建文件详细讲解

Linux中C语言open函数打开或创建文件详细讲解 头文件: #include #include #include 函数原型: int open( const char * pathname, int flags); int open( const char * pathname,int flags, mode_t mode); 作用:以各种方式打开文件 返回值:返回打开的文件句柄,-1打开失败 函数说明参数pathname指向欲打开的文件路径字符串,既可以是相对路径也可以是绝对路径。flags参数有一系列常数值可供选择,可以同时选择多个常数用按位或运算符连接起来,所以这些常数的宏定义都以O_开头,表示or 下列是参数flags所能使用的旗标: 必选项:以下三个常数中必须指定一个,且仅允许指定一个。 O_RDONLY以只读方式打开文件 O_WRONLY以只写方式打开文件 O_RDWR以可读写方式打开文件。上述三种旗标是互斥的,也就是不可同时使用,但可与下列的旗标利用OR(|)运算符组合。 以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags参数。 O_CREAT若欲打开的文件不存在则自动建立该文件。 O_EXCL如果O_CREAT也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。 O_NOCTTY如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。 O_TRUNC若文件存在并且以可写的方式打开时,此旗标会令文件长度清为0,而原来存于该文件的资料也会消失。 O_APPEND当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。 O_NONBLOCK以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。 O_NDELAY同O_NONBLOCK。 O_SYNC以同步的方式打开文件。

如何将32位的操作系统升级到64位

在讲方法前先声明一点,请务必检查你的电脑是否支持64位的系统。可以在驱动人生的驱动评估中去检测。 把windows7个32位版本和64位版本的镜像都下下来了却发现运行64系统的安装文件时提示:程序不是有效的32位程序如何升级呢?第一步:先把32位的iso系统文件和64位的iso系统文件用winRAR 解压出来,分别放在D盘和E盘的根目录下。 第二步:以管理员身份运行cmd,手工输入如下命令:d:setup /installfrom:e:sources/install.wim(注意:setup和/之间有一个空格) “/installfrom”参数指向64位的install.wim,这里的“d:setup”代表32位Windows 7,而“e:sources/install.wim”则表示来自64位Windows 7的安装镜像(具体盘符根据个人电脑不同可能有差别,大家自行修改吧)。 执行上述命令之后,立即就可以在32位系统上正常运行64位Windows 7的安装程序,是不是很简单?第三步:按照常见的安装32位windows7方法接着操作就行了。 安装感受:我是采用这种方法来安装64位的windows 7的,很方便.但是中间还是需要注意几点.

1.这种安装方法需要你有32位版本的安装文件(正好我两个版本的都有),全部解压到根目录下. 2.虽然方法中用到的命令行前面是32位安装文件中的setup 但应该是需要解压32位安装包中 全部的文件.(开始的时候我只把是setup文件提取出来,按照上边的方法,会提示缺少文件) 3.把64位的安装包解压到另一个磁盘,还要注意要把install.wim取出来,我的安装包中这个文件 在source文件夹中, 而上述命令是直接在根目录下寻找文件. Windows7纯净版下载大全(所有版本、中英繁体):https://www.doczj.com/doc/0d14765967.html,/a/caozuoxitong/Windows_7/20100520/23038.html VN网络万能激活工具(最新的Windows7激活工具):https://www.doczj.com/doc/0d14765967.html,/a/caozuoxitong/Windows_7/20100521/23365.html WIN7激活工具WIN7 Activation 1.7:https://www.doczj.com/doc/0d14765967.html,/a/caozuoxitong/Windows_7/20100527/23388.html 30多枚直接激活Windows7密钥:https://www.doczj.com/doc/0d14765967.html,/a/caozuoxitong/Windows_7/20100527/23389.html 最新20多枚密钥:https://www.doczj.com/doc/0d14765967.html,/a/caozuoxitong/Windows_7/20100527/23390.html 6K2KY-BFH24-PJW6W-9GK29-TMPWP

【IT专家】linux下打开chm格式文件

本文由我司收集整编,推荐下载,如有疑问,请与我司联系 linux下打开chm格式文件 首先我们安装一个打开chm文件的软件,这个软件叫chmsee. 在终端下运行:sudo apt-get install chmsee 安装完成后有可能还是打不开,这可能是系统升级时,如果xulrunner版本有变化,同样会导致chmsee无法运行,,查看/usr/lib中的xulrunner的版本(注:我的xulrunner的版本号为xulrunner-1.9)。然后建立下面四个链接:cd /usr/lib sudo ln -s xulrunner-1.9/libxul.so libxul.so sudo ln -s xulrunner-1.9/libxpcom.so libxpcom.so sudo ln -s xulrunner-1.9/libsqlite3.so libsqlite3.so sudo ln -s xulrunner-1.9/libmozjs.so libmozjs.so 如果还是有问题的话,可以试着把这四个链接删除掉然后再建立。其中删除链接的命令为:cd /usr/lib sudo rm libxul.so sudo rm libxpcom.so sudo rm libsqlite3.so sudo rm libmozjs.so ? ?在linux下打开chm格式文件的方式有多种,如:chmsee,chm-vewer等,但这些软件的安装要很多的依赖包,安装起来太烦,现在我向大家介绍一下firefox的chmreader插件,可通过fireforx打开chm文件,安装与使用都很方便。 ?1、从sourceforge/projects/chmreader下载chmreader. 2、从firefox中打开下载的xpi文件. 3、重新启动firefox就安装了chmreader插件. 4、打开chm文件(通过file中的open CHM files) 我打开chm文件的图:devhelp/htmlhelp/winhlp 帮助文件chm查看工具chm相关工具DevHelp/HtmlHelp/WinHelp帮助文件htmlhelp.berlios.de/ This project aims to provide: available reference documentation of open-source software in convienient HTML-based formats, such as Windows Compiled HTML Help (CHM) to provide the necessary tools for the generation of such books from the source documentation formats (may they be Texinfo, DocBook, LaTex, etc.), conversion among the diferent formats webserver based visualization (by hosting several books using MYSQL together with PHP or Python CGI scripts) platform-indenpendent GUI visualization tools perhaps a canonic XML based HTML help format LIDN: Linux Developer Network 这个站点有很多DevHelp书库。DevHelp是GNOME

怎样查看操作系统、cpu是32位还是64位

怎样查看操作系统是32位还是64位? Windows 7: 1.首先单击左下方的“开始”按钮,然后依次展开“控制面板—系统” 2.这时出现了“查看有关计算机的基本信息”窗口,我们将滚动条拉到最下面,有一 项“系统类型”,如果你的系统是32位这里就会显示32位操作系统,如果是64位则会显示64位操作系统。

Windows xp: 方法一: 1.在桌面上“我的电脑”鼠标右键单击“属性” 2.弹出了标题名为“系统属性”的窗口,在“常规”选项卡下记录您的系统是32位还 是64位的信息。如果您的系统是64位的,会明确标示出“x64 Edition”,否则您的系统就是32位的。

方法二: 1、单击“开始”,然后单击“运行” 2、在“打开”框中,键入 winmsd.exe,然后单击“确定” 3、在“项目”下面的右窗格中找到“处理器”。注意数值。 如果“处理器”对应的值是以“x86”开头的,则该计算机正在运行的是 Windows 操作系统的 32 位版本。

如果“处理器”对应的值是以“ia64”开头的,则该计算机正在运行的是 Windows 操作系统的 64 位版本。 4、或者:在“系统摘要”右窗格中找到“系统类型” 如果显示“基于 X86 的PC”,则该计算机正在运行的是 Windows 操作系统的32位版本; 如果为“基于 Itanium 的系统”,则该计算机正在运行的是 Windows 操作系统的64位版本。

1、开始>运行中键入“cmd”命令 2、然后在“命令提示符”窗口中输入“systeminfo”,按回车 3、如果您的系统是64位的,会在“OS 名称: Microsoft Windows XP Professional” 一行后明确标示出“x64 Edition”,否则您的系统就是32位的。

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Linux内核与跟文件系统的关系

Linux内核与根文件系统的关系 开篇题外话:对于Linux初学者来说,这是一个很纠结的问题,但这也是一个很关键的问题!一语破天机:“尽管内核是Linux 的核心,但文件却是用户与操作系统交互所采用的主要工具。这对Linux 来说尤其如此,这是因为在UNIX 传统中,它使用文件I/O 机制管理硬件 设备和数据文件。” 一.什么是文件系统 文件系统指文件存在的物理空间,linux系统中每个分区都是一个文件系统,都有自己的目 录层次结构。 Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其 中。这种机制有利于用户和操作系统的交互。 每个实际文件系统从操作系统和系统服务中分离出来,它们之间通过一个接口层:虚拟文件系统或VFS来通讯。VFS使得Linux可以支持多个不同的文件系统,每个表示一个VFS 的通用接口。由于软件将Linux 文件系统的所有细节进行了转换,所以Linux核心的其它部分及系统中运行的程序将看到统一的文件系统。Linux 的虚拟文件系统允许用户同时能透明地安装 许多不同的文件系统。 在Linux文件系统中,EXT2文件系统、虚拟文件系统、/proc文件系统是三个具有代表性的 文件系统。 二.什么是根文件系统 根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。 那么根文件系统在系统启动中到底是什么时候挂载的呢?先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后。切换根目录,再挂载具体的根文件系统.根文件系统执行完之后,也就是到了Start_kernel()函数的最后,执行init的进程,也就第一个用户进程。对系统进行各 种初始化的操作。 根文件系统之所以在前面加一个”根“,说明它是加载其它文件系统的”根“,既然是根的话,那么如果没有这个根,其它的文件系统也就没有办法进行加载的。它包含系统引导和使其他文件系统得以挂载(mount)所必要的文件。根文件系统包括Linux启动时所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在Linux挂载分区时Linux 一定会找/etc/fstab这个挂载文件等,根文件系统中还包括了许多的应用程序bin目录等,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。在Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt 目录上,/mnt目录下就有这个分区的各个目录,文件。

Linux新建文件命令

Linux新建文件命令 一、t ouch命令。 touch命令用来修改文件的访问时间、修改时间。如果没有指定时间,则将文件时间属性改为当前时间。当指定文件不存在,则touch命令变为创建该文件。 语法: 选项介绍: -a: 只修改访问时间; -c: 如果指定文件不存在,则不创建文件; -d STRING-time: 用字符串格式的时间来指定时间属性的修改值; -m: 只修改指定文件的修改时间; -r refernce-file: 将指定文件的时间属性改为与reference-file时间属性相同的值; -t [[CC]YY]MMDDhhmm[.ss]: 用[[CC]YY]MMDDhhmm[.ss]这种时间格式来指定时间属性的修改值; 执行范例: $ ls #查看当前空的目录 $ touch text #指定文件不存在,创建文件text $ stat text # stat命令可能查看文件的时间属性。 File: `text' Size: 0 Blocks: 8 IO Block: 4096 regular empty file Device: 831h/2097d Inode: 211271681 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 514/ xxxx) Gid: ( 100/ users) Access: 2010-03-01 22:03:30.000000000 +0800 Modify: 2010-03-01 22:03:30.000000000 +0800

Change: 2010-03-01 22:03:30.000000000 +0800 $ cat text # 读文件 $ stat text # 发现文件的访问时间(Access)改变 File: `text' Size: 0 Blocks: 8 IO Block: 4096 regular empty file Device: 831h/2097d Inode: 211271681 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 514/ xxxx) Gid: ( 100/ users) Access: 2010-03-01 22:04:08.000000000 +0800 Modify: 2010-03-01 22:03:30.000000000 +0800 Change: 2010-03-01 22:03:30.000000000 +0800 $ echo "hello world" > text # 相当于写文件 $ stat text # 发现文件的修改时间(Modify)改变 File: `text' Size: 12 Blocks: 16 IO Block: 4096 regular file Device: 831h/2097d Inode: 211271681 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 514/ xxxx) Gid: ( 100/ users) Access: 2010-03-01 22:04:08.000000000 +0800 Modify: 2010-03-01 22:04:58.000000000 +0800 Change: 2010-03-01 22:04:58.000000000 +0800 $ touch text #将文件的访问时间、修改时间改为当前时间 $ stat text File: `text' Size: 12 Blocks: 16 IO Block: 4096 regular file

谁知道 WIN7系统 32位和64位 有什么区别

谁知道WIN7系统32位和64位有什么区别? 最佳答案 简单的说x86代表32位操作系统x64代表64位操作系统。 如果你的CPU是双核以上,那肯定支持64位操作系统了 如果你的电脑内存大于4G,那就要用64位的系统了,因为32位的Windows 7也好,Vista也好,最大都只支持3.25G的内存。而64位的windows 7最大将支持128G的内存。 以下是引用网络上一段文字: 64bit计算主要有两大优点:可以进行更大范围的整数运算;可以支持更大的内存。 不能因为数字上的变化,而简单的认为64bit处理器的性能是32bit 处理器性能的两倍。实际上在32bit应用下,32bit处理器的性能甚至会更强,即使是64bit处理器,目前情况下也是在32bit应用下性能更强。所以要认清64bit处理器的优势,但不可迷信64bit。 更详细解答: 内存这是64位系统最显著的优点,它可以使用超过4GB的内存。大多数新的台式机和笔记本电脑至少拥有4GB的内存。问题是,像Vista和Win 7的32位版本只能够用大约3GB的内存。相比之

下,64位的Windows 不仅可以利用高达192GB的内存,还能够使用的内存映射取代BIOS的功能,从而使操作系统真正使用完整的 4GB的。因此,如果您安装Win7 x64,对于有的4GB内存的机器你不会浪费1GB内存。 个人认为,3GB不足够用于日常应用只是一个时间问题。一个例子是的Win 7的XP模式功能,它可以让你用旧的应用在一个虚拟机运行在Windows XP中。此功能可以用于各种目的,例如运行Office 2007和Office 2003年在同一台计算机上同时进行,或者是IE(对WEB开发很有用)。但WinXP模式需要至少512MB~1GB内存才能正常运行,因此XP模式非常吃内存。因此,如果您现在部署Windows 7 32位,那么你可能会很快要移动到64位,仅仅因为你必须升级您的机器与新的内存。我自己的笔记本电脑拥有8GB的内存,这是因为为了自己开发的程序在每个虚拟机环境下都能运行。我不想浪费内存中每一个字节。 64位真提供更好的性能了么? 我猜很多人认为64位处理器要快于32位处理器。因为有这样一个事实,从8位过渡到16位,从16位过渡到32位的过程确实带来了一些性能提升。基于以上的原因,是否可以认为64位的处理器可以更快?

Linux常用文件和目录类命令

常用文件和目录类命令练习linux (1)启动计算机,利用root用户登录到系统,进入字符提示界面。 (2)用pwd命令查看当前所在的目录。 (3)用ls命令列出此目录下的文件和目录。 (4)用-a选项列出此目录下包括隐藏文件在内的所有文件和目录。 (5)用man命令查看ls命令的使用手册。 (6)在当前目录下,创建测试目录test。 (7)利用ls命令列出文件和目录,确认test目录创建成功。 (8)进入test目录,利用pwd查看当前工作目录。 (9)利用touch命令在当前目录创建一个新的空文件newfile。 (10)利用cp命令复制系统文件/etc/profile到当前目录下。 (11)复制文本profile到一个新文件profile.bak,作为备份。 (12)用ll命令以长格式的形式列出当前目录下的所有文件,注意比较每个文件的 长度和创建时间的不同。 (13)用less命令分屏查看profile文件的内容,注意联系less命令的各个子命令, 例如b、p、q等并对“then”关键字查找。 (14)用grep命令在profile文件中对关键字“then”进行查询,并于上面的结果比 较。 (15)给文件profile创建一个软链接lnsprofile和一个硬链接lnhprofile。 (16)长格式显示文件profile、lnsprofile、lnhprofile的详细信息。注意比较3个文 件链接数的不同。 (17)删除文件profile,用长格式显示lnsprofile和lnhprofile的详细信息,比较文 件lnhprofile的链接数的变化。 (18)用less命令查看文件lnsprofile的内容,看看有什么结果。 (19)用less命令查看文件lnhprofile的内容,看看有什么结果。 (20)删除文件lnsprofile,显示当前目录下的文件列表,回到上层目录。 (21)用tar命令把目录打包。 (22)用gzip命令把打好的包进行压缩。 (23)把文件test.tar.gz改名为backup.tar.gz。 (24)显示当前目录下的文件和目录列表,确认重命名成功。 (25)把文件backup.tar.gz移动到test目录下。 (26)显示当前目录下的文件和目录列表,确认移动成功。 (27)进入test目录,显示目录中的文件列表。 (28)把文件test.tar.gz解包。 (29)显示当前目录下的文件和目录列表,复制test目录为testbak目录作为备份。 (30)查找root用户自己的主目录下所有名为newfile的文件。 (31)删除test子目录下的所有文件。 (32)利用rmdir命令删除空子目录test。 (33)回到上层目录,利用rm命令删除目录test和其下所有文件。

linux系统调用和文件操作

零、本课程能学到的内容 1、文件系统及文件的IO操作。 2、linux的多进程编程。 3、linux的多线程编程。 4、进程及线程之间的同步和异步通信 5、linux的网络编程(编写服务器、客户端、TCP、UDP程序)。 一、linux的系统调用 用户程序通过软中断的方式,让cpu切换到内核态运行,数据就借此传输。 对于CPU来说,它不知道现在运行是用户程序还是内核程序。软中断后,cpu根据拿到的数据,进行特定的任务,然后退出中断,将任务的结果交回给用户程序。 这个任务如何描述?是通过数字来编号的。 例子:写一个打印字符串的程序,通过系统调用来完成。 需要传递的参数有:指向字符串的指针(字符串的首地址),字符串的长度。 汇编写法 用int$0x80产生软中断 C的写法 直接使用syscall函数(它的本质就是用软中断来产生系统调用) 系统调用编号见:/usr/include/asm/unistd_32.h里 一共有358个。其中,4号对应的write调用。 二、linux文件系统基础 扇区(sector):磁头读取的最小单位数据,在磁盘上类似一个扇子的形状。一般是512个字节。 块(block):软件读取磁盘的最小单位数据,一般来说是扇区的2的n次幂大小,常用的有4096个字节。 块就是文件存放的最小单位。如果有一个文件是15045个字节,那么就分成4个块存储,最后那个块的数据是不满的。 可以用数组的方式将一个文件的所有数据块的编号保存起来。

这个数组多大合适? 前提是数组大小要固定,才好管理。 用一个15元素的数组来保存数据块的编号。 其中0-11元素,保存数据块的前面12个,第12个元素是一个一级指针,指向另一个表格,那个表格是4096字节,可以保存1024个块的编号。 如果还不够,第13个元素是一个二级指针,指向的那个表格是一级指针表格。14个元素是三级指针,指向的表格是二级指针表格。 全部用完可以存储2G大小的文件的数据块编号。 在文件系统内部,如何来表示一个文件呢? 用一个inode结构体来表示一个文件。inode是index node的意思。也叫索引节点。一个索引节点对应一个文件,有多少个文件就有多少个索引节点。 inode结构体里面有文件的大小、文件的修改时间、文件的权限、文件的数据块的编号数组。 inode结构体数组保存了所有文件的inode,这个数组的下标就是inode编号。文件名或者目录名保存目录文件的数据块里面。在linux里面,一个目录也是一个文件,叫做目录文件,其它的叫做普通文件。目录文件里就有,inode编号和文件名的对应关系。 那么,给出文件路径时,如何找到这个文件的数据块? /usr/include/stdio.h 首先,找到根目录的数据块,从里面找到文件和inode编号关系表, 例如usr这个文件名和inode编号为10002是对应的,那么就到inode结构体数组里找出下标为10002的元素,得到对应文件usr的数据块,因为usr也是一个文件夹,既然是文件夹,它的数据块里面也会有关系表,就可以找到include这个文件的数据块,最后找到stdio.h的数据块,这个是一个普通文件,就把它的数据块全部取出来。 这里搜索的起点是根目录的数据块,那么这个文件的数据块到哪里找? 在一个磁盘里面,最开始的几个块,存储了本磁盘的很多重要数据,例如块的大小,有哪些inode下标空闲,哪些已经用了,最重要的是根目录的数据块。 所有的参数存放在其中的一个块,这个块叫做超级块(super block)。在磁盘格式化,实际就是生成一个超级块。这个块的重要性毋庸置疑,如果数据被损坏,则磁盘没办法使用。 三、打开文件 在linux里面,用open函数就可以打开一个文件。 函数原型:int open(const char*path,int flag) 函数如果打开成功,则返回一个文件描述符f ile d escribtor,这个描述符fd是一个非负整数。 1、文件描述符

相关主题
文本预览
相关文档 最新文档