linux查看link 路径,link_path_walk()路径名查找

link_path_walk()路径名查找

link_path_walk()函数。它接收的参数为要解析的路径名指针name和拥有目录项信息和安装文件系统信息的nameidata数据结构的地址nd,此时nd的path字段存放的是查找的路径名的基目录的路径。其定义如下:

---------------------------------------------------------------------

fs/namei.c

/*

* Name resolution.

* This is the basic name resolution function,

turning a pathname into

* the final dentry. We expect 'base' to be

positive and a directory.

*

* Returns 0 and nd will have valid dentry and

mnt on success.

* Returns error and drops reference to input

namei data on failure.

*/

814 static int

link_path_walk(const char *name, struct nameidata *nd)

815 {

816struct path next;

817struct inode *inode;

818int err;

819unsigned int lookup_flags = nd->flags;

820

821while (*name=='/')

822name++;

823if (!*name)

824goto return_reval;

825

826inode =

nd->path.dentry->d_inode;

827if (nd->depth)

828lookup_flags = LOOKUP_FOLLOW |

(nd->flags & LOOKUP_CONTINUE);

829

830/* At this point we know we have a

real path component. */

831for(;;) {

832unsigned long hash;

833struct qstr this;

834unsigned int c;

835

836nd->flags |=

LOOKUP_CONTINUE;

837err = exec_permission(inode);

838if (err)

839break;

840

841this.name = name;

842c= *(const unsigned char *)name;

843

844hash = init_name_hash();

845do {

846name++;

847hash =

partial_name_hash(c, hash);

848c= *(const unsigned char *)name;

849} while (c && (c !=

'/'));

850this.len = name - (const char

*) this.name;

851this.hash =

end_name_hash(hash);

852

853/* remove trailing slashes? */

854if (!c)

855goto last_component;

856while (*++name == '/');

857if (!*name)

858goto

last_with_slashes;

859

860/*

861* "." and ".."

are special - ".." especially so because it has

862* to be able to know about

the current root directory and

863* parent relationships.

864*/

865if (this.name[0] == '.')

switch (this.len) {

866default:

867break;

868case 2:

869if

(this.name[1] != '.')

870break;

871follow_dotdot(nd);

872inode =

nd->path.dentry->d_inode;

873/* fallthrough

*/

874case 1:

875continue;

876}

877/* This does the actual

lookups.. */

878err = do_lookup(nd, &this,

&next);

879if (err)

880break;

881

882err = -ENOENT;

883inode = next.dentry->d_inode;

884if (!inode)

885goto out_dput;

886

887if

(inode->i_op->follow_link) {

888err =

do_follow_link(&next, nd);

889if (err)

890goto return_err;

891err = -ENOENT;

892inode =

nd->path.dentry->d_inode;

893if (!inode)

894break;

895} else

896path_to_nameidata(&next, nd);

897err = -ENOTDIR;

898if

(!inode->i_op->lookup)

899break;

900continue;

901/* here ends the main loop */

902

903 last_with_slashes:

904lookup_flags |= LOOKUP_FOLLOW

| LOOKUP_DIRECTORY;

905 last_component:

906/* Clear LOOKUP_CONTINUE iff

it was previously unset */

907nd->flags &=

lookup_flags | ~LOOKUP_CONTINUE;

908if (lookup_flags &

LOOKUP_PARENT)

909goto lookup_parent;

910if (this.name[0] == '.')

switch (this.len) {

911default:

912break;

913case 2:

914if

(this.name[1] != '.')

915break;

916follow_dotdot(nd);

917inode =

nd->path.dentry->d_inode;

918/* fallthrough

*/

919case 1:

920goto

return_reval;

921}

922err = do_lookup(nd, &this,

&next);

923if (err)

924break;

925inode =

next.dentry->d_inode;

926if (follow_on_final(inode,

lookup_flags)) {

927err =

do_follow_link(&next, nd);

928if (err)

929goto

return_err;

930inode =

nd->path.dentry->d_inode;

931} else

932path_to_nameidata(&next, nd);

933err = -ENOENT;

934if (!inode)

935break;

936if (lookup_flags &

LOOKUP_DIRECTORY) {

937err = -ENOTDIR;

938if

(!inode->i_op->lookup)

939break;

940}

941goto return_base;

942 lookup_parent:

943nd->last = this;

944nd->last_type = LAST_NORM;

945if (this.name[0] != '.')

946goto return_base;

947if (this.len == 1)

948nd->last_type =

LAST_DOT;

949else if (this.len == 2

&& this.name[1] == '.')

950nd->last_type =

LAST_DOTDOT;

951else

952goto return_base;

953 return_reval:

954/*

955* We bypassed the ordinary

revalidation routines.

956* We may need to check the cached dentry for

staleness.

957*/

958if (nd->path.dentry

&& nd->path.dentry->d_sb &&

959(nd->path.dentry->d_sb->s_type->fs_flags &

FS_REVAL_DOT)) {

960err = -ESTALE;

961/* Note: we do not

d_invalidate() */

962if

(!nd->path.dentry->d_op->d_revalidate(

963nd->path.dentry, nd))

964break;

965}

966 return_base:

967return 0;

968 out_dput:

969path_put_conditional(&next, nd);

970break;

971}

972path_put(&nd->path);

973 return_err:

974return err;

975 }

---------------------------------------------------------------------

这是一个非常长的函数。link_path_walk()执行下列步骤:

1、用nd->flags初始化lookup_flags局部变量(819行)。

2、跳过路径名第一个分量前的任何斜杠(/)(821行)。

3、如果剩余的路径名为空,则返回0。没有改变nameidata结构数据,nd->path中存放将要查找的路径名的基路径(823行)。

4、把将要查找的路径名的基路径的inode地址存放在局部变量inode中,即初始化最近一个所解析分量的索引节点对象的地址为将要查找的路径名的基路径的inode地址(826行)。

5、如果nd描述符中的depth字段(即符号链接嵌套的当前级别)的值为正(大于0),则把lookup_flags局部变量置为LOOKUP_FOLLOW标志(这个跟符号链接查找相关)(827行)。

6、执行一个循环,把name参数中传递的路径名分解为分量(中间的“/”被当做文件名分隔符对待)(831行);对于每个找到的分量,该函数:

a.设置lookup_flags局部变量置的LOOKUP_CONTINUE标志(836行)。

b.执行exec_permission(inode)函数检查存放到索引节点中的最近那个所解析分量的许可权是否允许执行(在Unix中,只有目录是可执行的,它才可以被遍历)(837行)。exec_permission()函数定义如下:

---------------------------------------------------------------------

fs/namei.c

463

static int exec_permission(struct inode *inode)

464

{

465int ret;

466

467if (inode->i_op->permission) {

468ret =

inode->i_op->permission(inode, MAY_EXEC);

469if (!ret)

470goto ok;

471return ret;

472}

473ret = acl_permission_check(inode,

MAY_EXEC, inode->i_op->check_acl);

474if (!ret)

475goto ok;

476

477if (capable(CAP_DAC_OVERRIDE) ||

capable(CAP_DAC_READ_SEARCH))

478goto ok;

479

480return ret;

481

ok:

482return

security_inode_permission(inode, MAY_EXEC);

483

}

---------------------------------------------------------------------

如果文件系统提供了inode->i_op->permission方法,则exec_permission()调用该例程执行EXEC权限检查,如果不允许执行则返回错误码,若允许,则调用security_inode_permission(),使用LSM的security_ops->inode_permission()方法来执行权限检查,并返回该方法的返回值。

inode->i_op->permission方法不存在,则调用acl_permission_check()执行基本的POSIX ACL权限检查,若通过检查,则调用security_inode_permission(),使用LSM的security_ops->inode_permission()方法来执行权限检查,并返回该方法的返回值。

若不通过,则执行权能检查,若同样不允许,则返回错误码。若允许,则调用security_inode_permission(),使用LSM的security_ops->inode_permission()方法来执行权限检查,并返回该方法的返回值。

如果最近所解析分量不允许执行,那么link_path_walk()跳出循环并返回一个错误码。

c.考虑要解析的下一个分量(841行-851行)。从它的名字,函数为目录项高速缓存散列表计算一个32位的散列值。

注意,这里用到了目录项名字数据结构qstr:

---------------------------------------------------------------------

include/linux/dcache.h

33

struct qstr {

34unsigned int hash;

35unsigned int len;

36const unsigned char *name;

37

};

---------------------------------------------------------------------

当前目录分量存放到了指向qstr结构的this局部变量中。

散列表的32位散列值如下计算:

---------------------------------------------------------------------

include/linux/dcache.h

50

#define init_name_hash()0

51

52

/* partial hash update function. Assume roughly 4 bits per character */

53

static inline unsigned long

54

partial_name_hash(unsigned long c, unsigned long prevhash)

55

{

56return (prevhash + (c << 4) + (c

>> 4)) * 11;

57

}

63

static inline unsigned long end_name_hash(unsigned long hash)

64

{

65return (unsigned int) hash;

66

}

---------------------------------------------------------------------

d.如果要解析的分量是原路径名中的最后一个分量,则跳到第last_component标号处去执行。后面“link_path_walk()对于路径名最后一个分量的处理”部分会有更详细的说明。

e.如果“/”终止了要解析的分量名,则跳过“/”之后的任何尾部“/”。多么强大的处理路径名的能力啊,也就是说路径名中两个目录之间是可以插入多个“/”。这一步为解析下一个分量做准备。而如果在一连串的“/”之后没有内容了,则跳转到标号last_with_slashes处执行。这是最后一个分量的特殊情况,也就是它必须一个目录。同样在后面“link_path_walk()对于路径名最后一个分量的处理”部分说明。

f.如果分量名是一个“.”(单个圆点),则继续下一个分量(“.”指的是当前目录,因此,这个点在目录内没有什么效果)(874行)。

g.如果分量名是“..”(两个圆点),则尝试回到父目录(871行)。这里面有个重要的follow_dotdot(nd)函数:

---------------------------------------------------------------------

fs/namei.c

670

static __always_inline void follow_dotdot(struct nameidata *nd)

671

{

672set_root(nd);

673

674while(1) {

675struct dentry *old =

nd->path.dentry;

676

677if (nd->path.dentry ==

nd->root.dentry &&

678nd->path.mnt ==

nd->root.mnt) {

679break;

680}

681if (nd->path.dentry !=

nd->path.mnt->mnt_root) {

682/* rare case of legitimate

dget_parent()... */

683nd->path.dentry =

dget_parent(nd->path.dentry);

684dput(old);

685break;

686}

687if (!follow_up(&nd->path))

688break;

689}

690follow_mount(&nd->path);

691

}

---------------------------------------------------------------------

(1)、首先,设置nd的root字段为当前进程的根路径。

(2)、如果最近解析的目录是进程的根目录(nd->path.dentry等于nd->root.dentry,而nd->path.mnt等于nd->root.mnt),那么再向上追踪是不允许的:在最近解析的分量上调用follow_mount()(见下面),继续下一个分量。

(3)、如果最近解析的目录不是nd->path.mnt文件系统的根目录(nd->path.dentry不等于nd->path.mnt->mnt_root,如果当前节点dentry不等于当前节点vfsmount对象的根设备的dentry,说明当前节点不是做为根节点被mount到其它设备上去的。在这里再来看vfsmount对象的mnt_mountpoint字段,它指向它挂载的目录的目录项,也就是原来的目录文件的信息),那么必须回到父目录:把nd->path.dentry置为其父目录的目录项,其实也就是nd-> path.dentry->

d_parent在父目录上调用follow_mount(&nd->path)(见下面),继续下一个分量。

(4)、如果最近解析的目录是nd->mnt文件系统的根目录,则调用函数follow_up(&nd->path)来处理,这个函数定义如下:

---------------------------------------------------------------------

fs/namei.c

599

int follow_up(struct path *path)

600

{

601struct vfsmount *parent;

602struct dentry *mountpoint;

603spin_lock(&vfsmount_lock);

604parent = path->mnt->mnt_parent;

605if (parent == path->mnt) {

606spin_unlock(&vfsmount_lock);

607return 0;

608}

609mntget(parent);

610mountpoint =

dget(path->mnt->mnt_mountpoint);

611spin_unlock(&vfsmount_lock);

612dput(path->dentry);

613path->dentry = mountpoint;

614mntput(path->mnt);

615path->mnt = parent;

616return 1;

617

}

---------------------------------------------------------------------

如果这个文件系统没有被安装在其他文件系统之上(path->mnt->mnt_parent等于path->mnt),那么

path->mnt文件系统通常就是进程命名空间的根文件系统:在这种情况下,再向上追踪是不可能的,因此在最近解析的分量上调用follow_mount()(参见下面),继续下一个分量。(这种情况是不应该出现的,或者说这种情况应该是在follow_dotdot的步骤(2)中就已经检测出来的)。

如果这个文件系统被安装在其他文件系统之上,那么就需要文件系统交换。因此,把path->dentry置为path->mnt->mnt_mountpoint,且把path->mnt置为 path->mnt->mnt_parent,然后重新开始第6g步(几个文件系统可以挂载在同一个挂载点上,在挂载的时候,原来的那个目录文件的vfsmount对象和目录项信息被保存在新的vfsmount对象的mnt_parent和mnt_mountpoint字段中)。

最后来看follow_mount(), follow_mount()定义如下:

---------------------------------------------------------------------

fs/namei.c

639

static void follow_mount(struct path *path)

640

{

641while (d_mountpoint(path->dentry))

{

642struct vfsmount *mounted =

lookup_mnt(path);

643if (!mounted)

644break;

645dput(path->dentry);

646mntput(path->mnt);

647path->mnt = mounted;

648path->dentry =

dget(mounted->mnt_root);

649}

650

}

---------------------------------------------------------------------

follow_mount()函数检查path ->dentry是否是某文件系统的挂载点(path-> dentry-> d_mounted的值大于0),如果不是,则直接退出。如果是,则调用lookup_mnt(),它的定义如下:

---------------------------------------------------------------------

fs/namespace.c

57

static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)

58

{

59unsigned long tmp = ((unsigned

long)mnt / L1_CACHE_BYTES);

60tmp += ((unsigned long)dentry /

L1_CACHE_BYTES);

61tmp = tmp + (tmp >> HASH_SHIFT);

62return tmp & (HASH_SIZE - 1);

63

}

414

struct vfsmount *__lookup_mnt(struct vfsmount *mnt,

415struct dentry

*dentry, int dir)

416

{

417struct list_head *head =

mount_hashtable + hash(mnt, dentry);

418struct list_head *tmp = head;

419struct vfsmount *p, *found = NULL;

420

421for (;;) {

422tmp = dir ? tmp->next :

tmp->prev;

423p = NULL;

424if (tmp == head)

425break;

426p = list_entry(tmp, struct vfsmount,

mnt_hash);

427if (p->mnt_parent == mnt

&& p->mnt_mountpoint == dentry) {

428found = p;

429break;

430}

431}

432return found;

433

}

439

struct vfsmount *lookup_mnt(struct path *path)

440

{

441struct vfsmount *child_mnt;

442spin_lock(&vfsmount_lock);

443if ((child_mnt =

__lookup_mnt(path->mnt, path->dentry, 1)))

444mntget(child_mnt);

445spin_unlock(&vfsmount_lock);

446return child_mnt;

447

}

---------------------------------------------------------------------

对于一个vfsmount来说,哈希值是根据其父vfsmount对象的地址和挂载点地址来计算的。

follow_mount()函数就是要找到挂载在本路径上的文件系统,即vfsmount对象的地址和目录项对象地址。

h.分量名既不是“.”,也不是“..”,调用do_lookup(nd, &this, &next)(878行),得到与给定的父目录(nd->path)和文件名(要解析的路径名分量&this)相关的目录项对象,存放在结果参数next中。这个函数完成实际的查找,是link_path_walk()函数的核心。后面会有更详细的说明。

i.检查刚解析的分量是否指向一个符号链接(next.dentry->d_inode具有一个i_op->follow_link方法)。将在后面“符号链接的查找”有更详细的说明。如果是则调用do_follow_link(&next, nd)做相应的处理。

j.刚解析的分量不是指向一个符号链接调用path_to_nameidata(&next,

nd),把nd->path.dentry和nd->path.mnt分别置为next.dentry和next.mnt,然后继续路径名的下一个分量:

---------------------------------------------------------------------

fs/namei.c

523

static inline void path_to_nameidata(struct path *path, struct nameidata *nd)

524

{

525dput(nd->path.dentry);

526if (nd->path.mnt != path->mnt)

527mntput(nd->path.mnt);

528nd->path.mnt = path->mnt;

529nd->path.dentry = path->dentry;

530

}

---------------------------------------------------------------------

k.检查刚解析的分量是否指向一个目录(next.dentry->d_inode具有一个自定义的i_op->lookup方法)。如果没有,返回一个错误码-ENOTDIR,因为这个分量位于原路径名的中间,然后continue继续路径名的下一个分量。主要的循环到此结束。

7、减少对查找到的path的引用计数并返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/496208.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【itext学习之路】--4.给pdf增加文本水印和图片水印

来源&#xff1a;【itext学习之路】-------&#xff08;第四篇&#xff09;给pdf增加文本水印和图片水印_tomatocc的博客-CSDN博客_itext添加水印 一般而言&#xff0c;许多公司在做pdf之后&#xff0c;都会将公司的logo或者网址以水印的方式添加到pdf文件中。本篇文章&#x…

Postman 使用方法详解

From&#xff1a;https://blog.csdn.net/fxbin123/article/details/80428216 Postman使用详解&#xff1a;https://www.cnblogs.com/xiaoxi-3-/p/7839278.html Postman用法简介&#xff1a;https://blog.csdn.net/flowerspring/article/details/52774399 Postman 详解&#xff…

该系列主要整理收集在使用C#开发WinForm应用文章及相关代码来源于WinForms小组...

该系列主要整理收集在使用C#开发WinForm应用文章及相关代码, 平时看到大家主要使用C#来开发Asp.Net应用,这方面的文章也特别多,而关于WinForm的文章相对少很多,而自己对WinForm一直比较感兴趣,这几年积累收藏了不少文章,现在整理一下分类推荐给大家,避免大家浪费大把的时间去找…

基于互联网大脑架构的腾讯未来趋势分析[系列1]

作者&#xff1a;刘锋&#xff0c;计算机博士 《互联网进化论》前言互联网大脑架构不是人为规划出来的&#xff0c;而是过去50年&#xff0c;互联网在科学探索和商业竞争两大动力推动下&#xff0c;形成的类脑架构。它的提出是基于2008年以来&#xff0c;我们对移动互联网&…

Linux看内存标压低压,三代锐龙、国产Linux上身笔记本电脑,性能是否和参数一样好看?...

原标题&#xff1a;三代锐龙、国产Linux上身笔记本电脑&#xff0c;性能是否和参数一样好看&#xff1f;如果你从很早开始就关注电脑行业&#xff0c;基本上你身边的朋友都会告诫你一句&#xff1a;“笔记本电脑千万别买AMD的……”并不是AMD不好&#xff0c;说实话&#xff0c…

【itext学习之路】--6.将html转成pdf(解决中文不显示)

来源&#xff1a;【itext学习之路】-------&#xff08;第七篇&#xff09;将html转成pdf(解决中文不显示)_tomatocc的博客-CSDN博客 在上一篇文章中&#xff0c;我们学习了使用对pdf进行盖章/签章/数字签名&#xff0c;到此为止&#xff0c;常用的pdf操作已经全部实现&#x…

Windows 安装 MongoDB 和 可视化工具Robo3T

MongoDB 官网下载地址&#xff1a;https://www.mongodb.com/try/download/community MongoDB 是一款非常热门的 NoSQL 面向文档的数据库管理系统&#xff0c; 分为 企业版收费版 和 社区免费版。MongoDB 使用 BSON 对象来存储&#xff0c;与 JSON 格式类型的 "键 - 值&quo…

【Vegas原创】VMWare安装Linux5的注意事项

1&#xff0c;VMWare版本需在6.5及以上。否则&#xff0c;在Linux桥接网络时&#xff0c;不能成功。 2&#xff0c;VMWare增强工具的安装问题请参看&#xff1a;http://www.cnblogs.com/vegaslee/archive/2009/09/22/1571671.html 3&#xff0c;VMWare下Linux的使用请参看&…

量子计算生态:市场预期、行业应用与“霸权”争夺

来源&#xff1a;资本实验室从IBM宣布推出业界首个商用量子计算系统&#xff0c;到我国开通全球首条量子通信干线并成功实现首次洲际量子通信&#xff0c;2017年的量子计算领域精彩不断&#xff0c;并不断提升市场对量子计算的预期。除了应用于国防安全&#xff0c;在科研、医疗…

linux下能运行python,(转)Linux下运行python

原文&#xff1a; http://blog.csdn.net/jackywgw/article/details/48847187在linux命令行下运行python&#xff0c;可以直接输出hello worldjackywgwjackywgw-A8F:~/python_learning$ pythonPython 3.3.6 (default, Apr 17 2015, 00:20:01)[GCC 4.9.2] on linuxType "hel…

xhtmlrenderer + iText-HTML转PDF

来源&#xff1a;xhtmlrenderer iText-HTML转PDF_hunan961的博客-CSDN博客_xhtmlrenderer xhtmlrendereitext2.0.8 将html转成pdf&#xff0c;带样式、图片(也支持二维码、条形码)等 主要步骤 生成html&#xff08;css样式直接放在style中&#xff09;html转换pdf方法数据返…

Ubuntu 防火墙 ufw

UbuntuHelp:UFW &#xff1a;http://wiki.ubuntu.org.cn/UbuntuHelp:UFW Ufw使用指南&#xff1a;http://wiki.ubuntu.org.cn/Ufw使用指南 ubuntu ufw防火墙&#xff1a;http://wap.dongnanshan.com/fn.php?subuntu ufw防火墙 UFW要领&#xff1a;通用防火墙规则和命令&#x…

NASA打算送机器蜜蜂去探索火星上的生命痕迹

来源&#xff1a;国际智能机器人用机械昆虫做侦察兵是科幻电影里存在了多年的场景&#xff0c;如今现实中已经有科学家在做这件事&#xff0c;譬如用机械蜜蜂探索太空。NASA最近就花了12.5万美元资助一个名为“Marsbees”的火星探测工具的科研项目。“Marsbees”是一款微型机器…

linux usb 驱动漏洞,不测不知道 这么多的USB漏洞要从何“补”起?

原标题&#xff1a;不测不知道 这么多的USB漏洞要从何“补”起?[PConline 杂谈]生活中&#xff0c;USB接口可以说无处不在&#xff0c;路由器、打印机、投影机、PC电脑、台式机等等&#xff0c;且使用频率极高。当然&#xff0c;作为硬件设备的输入输出接口&#xff0c;其安全…

小虎队 - 情难枕

现场感很好。。。时间在不远的前方穿梭&#xff0c;走在街头看着形色匆匆赶路回家的人群&#xff0c;这个城市&#xff0c;无声无息的变化........ 在这个意义上已到成熟的年纪&#xff0c;在茶语谈笑间总会想起往日的欢愉&#xff0c;在每个80后成长的人&#xff0c;那些昔日…

xhtmlrenderer 将html转换成pdf,完美css,带图片,手动分页,解决内容断开的问题

来源&#xff1a;xhtmlrenderer 将html转换成pdf&#xff0c;完美css&#xff0c;带图片&#xff0c;手动分页&#xff0c;解决内容断开的问题 - 煮过的花朵 - 博客园 之前用itext7将html导出为pdf&#xff0c;比较方便&#xff0c;代码较少&#xff0c;而且支持base64的图片。…

商汤科技宣布C轮战略融资6亿美元 阿里领投苏宁跟投

来源&#xff1a;雷帝网 人工智能平台公司商汤科技SenseTime宣布完成6亿美元C轮融资&#xff0c;由阿里巴巴集团领投&#xff0c;新加坡主权基金淡马锡、苏宁等投资机构和战略伙伴跟投。商汤科技联合创始人、CEO徐立表示&#xff1a;商汤科技C轮融资将进一步夯实公司在人工智能…

MongoDB Shell和Robo3T使用以及与SQL语法比较

From&#xff1a;MongoDB Shell 了解使用 - 大葱哥 - 博客园 MongoDB基本管理命令&#xff1a;MongoDB基本管理命令_千与的专栏-CSDN博客_mongo查询命令 MongoDB常用操作命令大全&#xff1a;MongoDB常用操作命令大全_piaocoder-CSDN博客_mongodb常用命令 mongodb 命令行基本…

PowerDesiGner数据库设计

原文地址&#xff1a;http://hi.baidu.com/shunkunl/blog/item/871c75ef8596faeace1b3e00.htmlPowerDesign&#xff1a;PowerDesign是 Sybase推出的主打数据库设计工具。PowerDesign致力于采用基于Entiry-Relation的数据模型&#xff0c;分别从概念数据模型 (Conceptual Data M…

mipony linux客户端,Mipony网盘下载工具

Mipony是一个特别设计的下载管理器下载的免费网盘如Rapidshare&#xff0c;Megaupload&#xff0c;Hotfiles&#xff0c;Gigasize&#xff0c;Filefactory&#xff0c;Mediafire&#xff0c;Netload。简介&#xff1a;支援“HJSplit”档案合并功能&#xff0c;还可以自动侦测网…