Linux ext2, ext3, ext4 文件系统解读[2]
来源:互联网 发布:印尼屠侨真相知乎 编辑:程序博客网 时间:2024/05/22 14:17
目录与文件:
从前面Inode的结构中我们可以看到,其中并没有定义文件名称,文件名称实际是存放在目录中的,目录也是一类特殊的文件,在ext2文件系统中,目录是由ext2_dir_entry结构组成的列表,目录是变长的结构,这样可以避免磁盘空间的浪费。对于单个文件名,长度不能超过255字符,且文件名的长度会自动使用'\0'字符填充为4个整数倍。目录中有文件和子目录。
ext2_dir_entry结构:
/*
* Structure of a directory entry
*/
#define EXT2_NAME_LEN 255
struct ext2_dir_entry {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u16 name_len; /* Name length */
char name[EXT2_NAME_LEN]; /* File name */
};
上面是老版本的定义,新版本的结构定义:
/*
* The new version of the directory entry. Since EXT2 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext2_dir_entry_2 {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT2_NAME_LEN]; /* File name */
};
可以看到,新版本中,将文件名的长度的属性从16比特修改为8比特,将剩余的8比特用于记录文件类型。
文件类型定义:
/ *
* Ext2 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
enum {
EXT2_FT_UNKNOWN, /*未知*/
EXT2_FT_REG_FILE, /*普通文件*/
EXT2_FT_DIR, /*目录文件*/
EXT2_FT_CHRDEV, /*字符设备*/
EXT2_FT_BLKDEV, /*块设备*/
EXT2_FT_FIFO, /*管道*/
EXT2_FT_SOCK, /*套接字*/
EXT2_FT_SYMLINK, /*符号链接*/
EXT2_FT_MAX /*文件类型枚举的结尾标识*/
};
无论何种类型的文件,都对应一个Inode,Inode号在结构中inode属性记录。不同类型的文件使用Data Block的方式并不相同。有的文件不用来存放数据,不使用Data Block。下面是不同类型的文件使用Data Block的说明:
普通文件:
普通文件在创建时是空的,再向其中写入数据的时候,会为其分配Data Block。
目录文件:
目录文件的Data Block中存放的就是上面的ext2_dir_entry结构(或者是新的结构),name长度可变,最大不会超过255。rec_len记录了目录的大小,将它与这个目录的起始地址相加,就得到了下一个有效目录的起始地址,所以rec_len也可以看做是下一个有效目录的指针。要删除当前这个目录,只需要将inode置为0,并增加前一个目录的rec_len的值,以“跳过”当前这个删除的目录。
符号链接(软连接):
如果符号链接的路径名称小于60个字符,则使用Inode的i_block数组直接存放其值(15*4字节=60字节),如果超出60了字符,则需要为其分配一个Block,并将i_block中的指针指向对应的Block。
设备文件,管道,套接字:
这些文件类型不需要Block,所有信息都存放在Inode中。
下面是一个小例子,说明了ext2文件系统中,是如何利用目录来读出一个文件内容的,顺便也熟悉一下debugfs调试工具:
我们将1023GB的磁盘(分区:/dev/sdd1)使用ext2格式化,然后挂载到/mnt/sdd下,在下面创建了几个目录和文件,结构如下:
/mnt/sdd
/mnt/sdd/root_inode_debugfs
/mnt/sdd/test/new1.txt
/mnt/sdd/test/testlnk.txt -> test.txt
/mnt/sdd/test/test.txt
/mnt/sdd/test/test1/2.txt
/mnt/sdd/test/test2/2.txt
首先,输入debugfs,进入调试:
[root@DanCentOS65 daniel]# debugfs
debugfs 1.41.12 (17-May-2010)
debugfs:
接着使用open打开要调试的设备:
debugfs: open /dev/sdd1
查看根目录的详细信息:
debugfs: ls -l
2 40755 (2) 0 0 4096 21-Apr-2017 03:21 .
2 40755 (2) 0 0 4096 21-Apr-2017 03:21 ..
11 40700 (2) 0 0 16384 20-Apr-2017 14:16 lost+found
12 100644 (1) 0 0 4096 21-Apr-2017 02:49 root_inode_debugfs
855681 40755 (2) 0 0 4096 21-Apr-2017 07:30 test
每一列的说明:
- 第一列为Inode号
- 第二列表示文件权限(前三位是suid/sgid/ticky,后三位的User/Group/Others的权限)
- 第三列是文件类型,(2)对应目录,(1)对应普通文件,具体可以参考一下前面ext2文件类型的枚举
- 第四列表示文件/目录的ownerid
- 第五列表示文件/目录的groupid
- 第六列表示文件占用的大小,可以除以Block大小得到文件占用的Block数量
- 第七列表示创建时间
- 最后一列是目录的名称
注意到上面输出结果中有两个特殊的目录“.”和“..”,这两个目录不能删除,用于相对路径的查找,“.”表示当前目录,“..”表示父目录。
言归正传,我们以/mnt/sdd/test/test2/2.txt来说明文件的读取过程:
我们当前查看的目录其实就是/dev/sdd1的挂载点的目录,即/mnt/sdd,所以在结果中看到的“.”目录对应的Inode号为2,也就是/mnt/sdd的根Inode号是2,进一步查看Inode 2的内容,首先通过命令将Inode 2的内容输出到文件中:
debugfs: dump_inode <2> dump1
接着在另一个终端中使用vi -b打开dump1文件(注意,上面dump1文件的存放目录是进入debugfs之前的那个目录,而不是我们调试的那个目录):
[root@DanCentOS65 daniel]# vi -b dump1
^B^@^@^@^L^@^A^B.^@^@^@^B^@^@^@^L^@^B^B..^@^@^K^@^@^@$^@
^Blost+found^@^@^@^@^@^@^P^@^E^A1.txt^@^@^@^L^@^@^@D^@^R^Aroot_inode_debugfs^F^A^@^@^@^@
(^@^L^Adir1_debugfs^@^@^@^@^T^@^K^Adev_debugfs^@<81>^N^M^@<80>^O^D^Btest^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
……
上面的结果中显示了目前Inode 2中存放的内容,其中有一些乱码先忽略掉,我们先查看可读的文件名。细心的读者可能会发现除了我们在目录中看到的lost+found目录,test目录以及root_inode_debugfs文件之外,还有1.txt和dir1_debugfs两个文件,其实这两个文件之前确实是存在的,后来删除掉了,由于删除其实仅仅是修改对应的Inode和Block的标记位,在没有新的内容覆盖掉其内容之前,这些旧的条目会一直都在磁盘上,所以这里我们才能看到对应的内容,这也是一些磁盘数据恢复工具的原理所在。
当我们尝试打开/mnt/sdd/test/test2/2.txt时,文件系统首先会根据目录/mnt/sdd得到其Inode号2,并且确认其权限有读权限,从中读出Block中的内容,也就是上面这些子目录和文件的内容,从中找到我们要访问的下一个目录test,并找到对应的Inode号码855681(从上面的结果中可以看到)。接着系统会读取Inode 855681的内容:
. ntest2.tx
<81>^N^M^@^L^@^A^B.^@^@^@^B^@^@^@^L^@^B^B..^@^@<85>^N^M^@^P^@^H^Anew1.txt<82>^N^M^@^P^@^E^Btest1t.s^A^
O^M^@^P^@^E^Btest2.tx<83>^N^M^@^X^@^K^Gtestlnk.txtwp^@^@^@<84>^N^M^@<a0>^O^H^Atest.txtt.swx^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@......
同理,文件系统会从中找到下一级目录test2,并找到他的Inode编号855809:
debugfs: ls -l test
855681 40755 (2) 0 0 4096 21-Apr-2017 08:09 .
2 40755 (2) 0 0 4096 21-Apr-2017 09:14 ..
855685 100644 (1) 0 0 15 21-Apr-2017 06:54 new1.txt
855682 40755 (2) 0 0 4096 21-Apr-2017 05:04 test1
855809 40755 (2) 0 0 4096 21-Apr-2017 05:05 test2
855683 120777 (7) 0 0 8 21-Apr-2017 08:09 testlnk.txt
855684 100644 (1) 0 0 58 21-Apr-2017 07:30 test.txt
继续读取其中内容:
^A^O^M^@^L^@^A^B.^@^@^@<81>^N^M^@^L^@^B^B..^@^@^D^O^M^@<e8>^O^E^A2.txt^@^@^@^@^@^@^@<d8>^O
^A.2.txt.swp^@^@^@^@^@^@<c4>^O^F^A2.txt~.swx^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
进一步得到2.txt的Inode号,最终从Data Block中读出文件数据。
调试完成后,可以使用close关闭打开的设备:
debugfs: close
需要注意的是,在调试过程中,如果我们在其他终端中对这个文件系统的文件或者目录进行调整,是不会反映到当前Debug的过程中的,想要重新载入修改的目录和文件,需要退出debugfs,重新mount一下分区,再次打开debugfs即可。
除了上面列出的命令之外,还有很多其他命令可以使用,例如可以使用features查看superblock中定义的功能特性,使用stat <inode number>查看对应的Inode的结构信息,使用stats可以查看superblock的结构等等,有兴趣的读者可以使用?查看全部命令(也可以使用man debugfs查看更详细的用户手册):
debugfs: ?
Available debugfs requests:
show_debugfs_params, params
Show debugfs parameters
open_filesys, open Open a filesystem
close_filesys, close Close the filesystem
feature, features Set/print superblock features
dirty_filesys, dirty Mark the filesystem as dirty
init_filesys Initialize a filesystem (DESTROYS DATA)
show_super_stats, stats Show superblock statistics
ncheck Do inode->name translation
icheck Do block->inode translation
change_root_directory, chroot
Change root directory
change_working_directory, cd
Change working directory
list_directory, ls List directory
show_inode_info, stat Show inode information
dump_extents, extents, ex
Dump extents information
link, ln Create directory link
unlink Delete a directory link
mkdir Create a directory
rmdir Remove a directory
rm Remove a file (unlink and kill_file, if appropriate)
kill_file Deallocate an inode and its blocks
clri Clear an inode's contents
freei Clear an inode's in-use flag
seti Set an inode's in-use flag
testi Test an inode's in-use flag
freeb Clear a block's in-use flag
setb Set a block's in-use flag
testb Test a block's in-use flag
modify_inode, mi Modify an inode by structure
find_free_block, ffb Find free block(s)
find_free_inode, ffi Find free inode(s)
print_working_directory, pwd
Print current working directory
expand_dir, expand Expand directory
mknod Create a special file
list_deleted_inodes, lsdel
List deleted inodes
undelete, undel Undelete file
write Copy a file from your native filesystem
dump_inode, dump Dump an inode out to a file
cat Dump an inode out to stdout
lcd Change the current directory on your native filesystem
rdump Recursively dump a directory to the native filesystem
set_super_value, ssv Set superblock value
set_inode_field, sif Set inode field
set_block_group, set_bg Set block group descriptor field
logdump Dump the contents of the journal
htree_dump, htree Dump a hash-indexed directory
dx_hash, hash Calculate the directory hash of a filename
dirsearch Search a directory for a particular filename
bmap Calculate the logical->physical block mapping for an inode
imap Calculate the location of an inode
dump_unused Dump unused blocks
set_current_time Set current time to use when setting filesystme fields
supported_features Print features supported by this version of e2fsprogs
help Display info on command or topic.
list_requests, lr, ? List available commands.
quit, q Leave the subsystem.
除了上面说的dumpe2fs和debugfs中的调试命令之外,下面也是一些常用的查看命令:
通过-i参数在输出结果中查看Inode编号:
[root@DanCentOS65 test]# ls -il
total 16
855685 -rw-r--r-- 1 root root 15 Apr 21 06:54 new1.txt
855682 drwxr-xr-x 2 root root 4096 Apr 21 05:04 test1
855809 drwxr-xr-x 2 root root 4096 Apr 21 05:05 test2
855683 lrwxrwxrwx 1 root root 8 Apr 21 08:09 testlnk.txt -> test.txt
855684 -rw-r--r-- 1 root root 58 Apr 21 07:30 test.txt
stat命令查看目录或文件对应的Inode信息:
[root@DanCentOS65 test]# stat test2
File: `test2'
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 831h/2097d Inode: 855809 Links: 2
Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-04-21 05:35:58.000000000 +0000
Modify: 2017-04-21 05:05:08.000000000 +0000
Change: 2017-04-21 05:05:08.000000000 +0000
查看Inode使用情况:
[root@DanCentOS65 daniel]# df -ih
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda1 1.9M 98K 1.8M 6% /
tmpfs 873K 1 873K 1% /dev/shm
/dev/sdb1 18M 12 18M 1% /mnt/resource
/dev/sdf1 1.9M 36K 1.9M 2% /mnt/ubuntu
/dev/sdd1 1023K 20 1023K 1% /mnt/sdd
顺便再补充一下软连接和硬链接的知识:
我们接着上面的例子,再创建一个硬链接:
[root@DanCentOS65 daniel]# ll /mnt/sdd/test
total 20
-rw-r--r-- 2 root root 15 Apr 21 06:54 new1HDlnk
-rw-r--r-- 2 root root 15 Apr 21 06:54 new1.txt
drwxr-xr-x 2 root root 4096 Apr 21 05:04 test1
drwxr-xr-x 2 root root 4096 Apr 21 05:05 test2
lrwxrwxrwx 1 root root 8 Apr 21 08:09 testlnk.txt -> test.txt
-rw-r--r-- 1 root root 58 Apr 21 07:30 test.txt
上面的目录中new1HDlnk文件是new1.txt的硬链接,testlnk.txt是test.txt的软连接,我们还是用debugfs来看一下二者的区别:
debugfs: ls -l test
855681 40755 (2) 0 0 4096 21-Apr-2017 09:47 .
2 40755 (2) 0 0 4096 21-Apr-2017 09:14 ..
855685 100644 (1) 0 0 15 21-Apr-2017 06:54 new1.txt
855682 40755 (2) 0 0 4096 21-Apr-2017 05:04 test1
855809 40755 (2) 0 0 4096 21-Apr-2017 05:05 test2
855683 120777 (7) 0 0 8 21-Apr-2017 08:09 testlnk.txt
855684 100644 (1) 0 0 58 21-Apr-2017 07:30 test.txt
855685 100644 (1) 0 0 15 21-Apr-2017 06:54 new1HDlnk
可以明显看到,硬链接new1HDlnk实际上仅仅是源文件的一个别名,写到了上级目录的Data Block中,它是没有自己的Inode的,所以它的Inode号855685其实也就是源文件new1.txt的Inode号。而软连接不同,软连接是一类特殊的文件,有自己的Inode和内容。上面例子中,源文件test.txt的文件名小于60字节,所以我们可以看到testlnk.txt的Inode中并没有分配Data Block:
debugfs: stat <855683>
Inode: 855683 Type: symlink Mode: 0777 Flags: 0x0
Generation: 2285856085 Version: 0x00000000
User: 0 Group: 0 Size: 8
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 0
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x58f9be38 -- Fri Apr 21 08:09:28 2017
atime: 0x58f9be39 -- Fri Apr 21 08:09:29 2017
mtime: 0x58f9be38 -- Fri Apr 21 08:09:28 2017
Size of extra inode fields: 0
Fast_link_dest: test.txt
我们在做一个测试,创建一个超过60字节文件名的文件file0123456789012345678901234567890123456789012345678901234567890123456789.txt,并为其创建一个软连接largerlnk:
[root@DanCentOS65 test]# ll
total 28
-rw-r--r-- 1 root root 71 Apr 22 08:35 file0123456789012345678901234567890123456789012345678901234567890123456789.txt
lrwxrwxrwx 1 root root 78 Apr 22 08:36 largerlnk -> file0123456789012345678901234567890123456789012345678901234567890123456789.txt
-rw-r--r-- 2 root root 15 Apr 21 06:54 new1HDlnk
-rw-r--r-- 2 root root 15 Apr 21 06:54 new1.txt
drwxr-xr-x 2 root root 4096 Apr 21 05:04 test1
drwxr-xr-x 2 root root 4096 Apr 21 05:05 test2
lrwxrwxrwx 1 root root 8 Apr 21 08:09 testlnk.txt -> test.txt
-rwxr-xr-x 1 root root 58 Apr 21 07:30 test.txt
再来看一下largerlnk对应的Inode:
debugfs: ls -l
855681 40755 (2) 0 0 4096 22-Apr-2017 08:36 .
2 40755 (2) 0 0 4096 21-Apr-2017 09:14 ..
855685 100644 (1) 0 0 15 21-Apr-2017 06:54 new1.txt
855682 40755 (2) 0 0 4096 21-Apr-2017 05:04 test1
855809 40755 (2) 0 0 4096 21-Apr-2017 05:05 test2
855683 120777 (7) 0 0 8 21-Apr-2017 08:09 testlnk.txt
855684 100755 (1) 0 0 58 21-Apr-2017 07:30 test.txt
855685 100644 (1) 0 0 15 21-Apr-2017 06:54 new1HDlnk
855687 120777 (7) 0 0 78 22-Apr-2017 08:36 largerlnk
855688 100644 (1) 0 0 71 22-Apr-2017 08:35 file0123456789012345678901234567890123456789012345678901234567890123456789.txt
debugfs: stat <855687>
Inode: 855687 Type: symlink Mode: 0777 Flags: 0x0
Generation: 2439924333 Version: 0x00000000
User: 0 Group: 0 Size: 78
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x58fb1607 -- Sat Apr 22 08:36:23 2017
atime: 0x58fb1608 -- Sat Apr 22 08:36:24 2017
mtime: 0x58fb1607 -- Sat Apr 22 08:36:23 2017
Size of extra inode fields: 0
BLOCKS:
(0):219056128
TOTAL: 1
可以看到,当指向的文件名超过60字节时,就不能在Inode的i_block中直接存放指向的文件名了,此时文件系统会分配一个Data Block,我们看到Data Block的编号为219056128,查看一下其中的内容(当然直接在debugfs中通过cat也可以查看,只不过这里演示一下如何使用dd来读取Data Block的数据):
[root@DanCentOS65 test]# dd if=/dev/sdc1 of=block.txt skip=219056128 ibs=4096 bs=4096 count=1
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.00018398 s, 22.3 MB/s
[root@DanCentOS65 test]# vi block.txt
file0123456789012345678901234567890123456789012345678901234567890123456789.txt^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@……
可以看到,Data Block中存放的就是指向的文件的名称。
注:dd命令参数简要说明:
if=file #输入文件名,缺省为标准输入
of=file #输出文件名,缺省为标准输出
ibs=bytes #一次读入 bytes 个字节(即一个块大小为 bytes 个字节)
obs=bytes #一次写 bytes 个字节(即一个块大小为 bytes 个字节)
bs=bytes #同时设置读写块的大小为 bytes ,可代替 ibs 和 obs
cbs=bytes #一次转换 bytes 个字节,即转换缓冲区大小
skip=blocks #从输入文件开头跳过 blocks 个块后再开始复制
seek=blocks #从输出文件开头跳过 blocks 个块后再开始复制
count=blocks #仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数
conv=conversion[,conversion...] #用指定的参数转换文件
- Linux ext2, ext3, ext4 文件系统解读[2]
- Linux ext2, ext3, ext4 文件系统解读[1]
- Linux ext2, ext3, ext4 文件系统解读[3]
- Linux ext2, ext3, ext4 文件系统解读[4]
- Linux ext2, ext3, ext4 文件系统解读[5]
- Linux 文件系统ext2, ext3, ext4
- ext2、ext3、ext4文件系统区别
- Linux文件系统Ext2,Ext3,Ext4性能大比拼
- linux系统下EXT2/EXT3/EXT4文件系统的数据恢复
- Linux ext2 ext3 ext4 比较
- Linux ext2/ext3文件系统
- Linux文件系统:ext2/ext3
- ext2、ext3、ext4、brtfs文件系统区别
- ext2、ext3、ext4、brtfs文件系统区别
- 模块化编译ext2, ext3,ext4 文件系统
- Linux分区类型EXT2、EXT3、EXT4详解
- Linux ext2/ext3文件系统详解
- Linux ext2/ext3文件系统详解
- Linux sed的原理和用法
- 多继承与多重继承
- 基于jQuery实现的点击编辑按钮时传递参数到弹出层div
- sql语句删除重复行
- Hihocoder #1284 : 机会渺茫
- Linux ext2, ext3, ext4 文件系统解读[2]
- 编写高效且优雅的 Python 代码
- 第二章 递归与分治策略(排列的字典序问题)
- Oracle笔记1
- 神经网络sim实现原理,及原理坑的方法。
- centOS6.5安装sphinx扩展
- 面向对象—静态代码块+构造代码块+局部代码块
- 易错的api和坑
- 9273:PKU2506Tiling