cygwin下的/etc/fstab

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

Cygwin checkout-2008-09-28

vs2008

欢迎转载,但请保留作者信息

cygwin初始化的时候,会查询根目录下是否有/etc/fstab文件,如果这个文件存在,cygwin将读取它,从中取得windows路径和posix路径之间的映射关系。

本文尝试对此做一点分析。

1.1 mount_info::init

cygwin初始化的时候,将调用一个叫mount_info::init的函数,其调用栈如下:

> cygwin.dll!mount_info::init() 116 + 0x15 字节 C++

cygwin.dll!user_shared_initialize() 227 C++

cygwin.dll!dll_crt0_1(void * __formal=0x00000000) 898 C++

cygwin.dll!_cygtls::call2(unsigned long (void *, void *)* func=0x10012000, void * arg=0x00000000, void * buf=0x00216fb8) 72 + 0xd 字节 C++

cygwin.dll!_cygtls::call(unsigned long (void *, void *)* func=0x10012000, void * arg=0x00000000) 66 C++

cygwin.dll!_dll_crt0() 1082 + 0xc 字节 C++

cygwin.dll!cygwin_dll_init() 1121 C++

bash.exe!main(int argc=0x00000003, char * * argv=0x00c56748) 769 + 0x8 字节 C

看看这个函数做了什么事情:

void

mount_info::init ()

{

nmounts = 0;

PWCHAR pathend;

WCHAR path[PATH_MAX];

pathend = wcpcpy (path, cygwin_shared->installation_root);

create_root_entry (path);

pathend = wcpcpy (pathend, L"\\etc\\fstab");

if (from_fstab (false, path, pathend) /* The single | is correct! */

| from_fstab (true, path, pathend))

return;

/* FIXME: Remove warning message before releasing 1.7.0. */

small_printf ("Huh? No /etc/fstab file in %W? Using default root and cygdrive prefix...\n", path);

}

在这里cygwin_shared->installation_root取值为正在运行的exe文件所在目录的上一级目录,比如exe文件为

"\??\f:\embed\etools\Debug\bin\bash.exe"

cygwin_shared->installation_root的值就是

"\??\f:\embed\etools\Debug\"

这段代码将这个路径传入from_fstab函数,继续往下看:

bool

mount_info::from_fstab (bool user, WCHAR fstab[], PWCHAR fstab_end)

{

UNICODE_STRING upath;

OBJECT_ATTRIBUTES attr;

CYG_IO_STATUS_BLOCK io;

NTSTATUS status;

HANDLE fh;

…………….

RtlInitUnicodeString (&upath, fstab);

InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);

debug_printf ("Try to read mounts from %W", fstab);

status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, &attr, &io,

FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT);

if (!NT_SUCCESS (status))

{

debug_printf ("NtOpenFile(%S) failed, %p", &upath, status);

return false;

}

char buf[NT_MAX_PATH];

char *got = buf;

DWORD len = 0;

unsigned line = 1;

/* Using buffer size - 2 leaves space to append two \0. */

while (NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, got,

(sizeof (buf) - 2) - (got - buf), NULL, NULL)))

{

char *end;

len = io.Information;

/* Set end marker. */

got[len] = got[len + 1] = '\0';

/* Set len to the absolute len of bytes in buf. */

len += got - buf;

/* Reset got to start reading at the start of the buffer again. */

got = buf;

retry:

bool got_nl = false;

while (got < buf + len && (end = strchr (got, '\n')))

{

got_nl = true;

end[end[-1] == '\r' ? -1 : 0] = '\0';

if (!from_fstab_line (got, user))

goto done;

got = end + 1;

++line;

}

if (len < (sizeof (buf) - 2))

break;

/* Check if the buffer contained at least one \n. If not, the

line length is > 32K. We don't take such long lines. Print

a debug message and skip this line entirely. */

if (!got_nl)

{

system_printf ("%W: Line %d too long, skipping...", fstab, line);

while (NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, buf,

(sizeof (buf) - 2), NULL, NULL)))

{

len = io.Information;

buf[len] = buf[len + 1] = '\0';

got = strchr (buf, '\n');

if (got)

{

++got;

++line;

goto retry;

}

}

got = buf;

break;

}

/* We have to cyg_read once more. Move remaining bytes to the start of

the buffer and reposition got so that it points to the end of

the remaining bytes. */

len = buf + len - got;

memmove (buf, got, len);

got = buf + len;

buf[len] = buf[len + 1] = '\0';

}

/* Catch a last line without trailing \n. */

if (got > buf)

from_fstab_line (got, user);

done:

NtClose (fh);

return true;

}

很显然,这一段代码将从fstab文件中一行一行地取出数据,并将此行字符串的指针传递给from_fstab_line函数,对每行数据的分析由from_fstab_line函数完成。

1.2 fstab的文件格式

由于cygwin对每一行数据的分析都是通过from_fstab_line函数完成的,因此我们直接看看它做了什么:

bool

mount_info::from_fstab_line (char *line, bool user)

{

char *native_path, *posix_path, *fs_type;

/* First field: Native path. */

char *c = skip_ws (line);

if (!*c || *c == '#')

return true;

char *cend = find_ws (c);

*cend = '\0';

native_path = conv_fstab_spaces (c);

/* Second field: POSIX path. */

c = skip_ws (cend + 1);

if (!*c)

return true;

cend = find_ws (c);

*cend = '\0';

posix_path = conv_fstab_spaces (c);

/* Third field: FS type. */

c = skip_ws (cend + 1);

if (!*c)

return true;

cend = find_ws (c);

*cend = '\0';

fs_type = c;

/* Forth field: Flags. */

c = skip_ws (cend + 1);

if (!*c)

return true;

cend = find_ws (c);

*cend = '\0';

unsigned mount_flags = MOUNT_SYSTEM | MOUNT_BINARY;

if (!read_flags (c, mount_flags))

return true;

if (user)

mount_flags &= ~MOUNT_SYSTEM;

if (!strcmp (fs_type, "cygdrive"))

{

cygdrive_flags = mount_flags | MOUNT_CYGDRIVE;

slashify (posix_path, cygdrive, 1);

cygdrive_len = strlen (cygdrive);

}

else

{

int res = mount_table->add_item (native_path, posix_path, mount_flags);

if (res && get_errno () == EMFILE)

return false;

}

return true;

}

从这个函数可以很清楚地看出每一行数据的意义:

如果这个行以#号开关,那么它是一个注释。否则就认为这是一行有意义的数据。

每一行数据有4个字段,每个字段间以’\t’做为分隔符号。

第一个字段为windows本地路径,比如c:\windows之类的。

第二个字段为对应的posix路径名称,比如/windows

第三个字段为文件系统类型,但是从这段代码可以看出,只有当它为“cygdrive”时有特殊意义,否则丢弃这个段的内容。

最后一个是特殊标志,它的允许取值来自于下面的定义:

struct opt

{

const char *name;

unsigned val;

bool clear;

} oopts[] =

{

{"user", MOUNT_SYSTEM, 1},

{"nouser", MOUNT_SYSTEM, 0},

{"binary", MOUNT_BINARY, 0},

{"text", MOUNT_BINARY, 1},

{"exec", MOUNT_EXEC, 0},

{"notexec", MOUNT_NOTEXEC, 0},

{"cygexec", MOUNT_CYGWIN_EXEC, 0},

{"nosuid", 0, 0},

{"acl", MOUNT_NOACL, 1},

{"noacl", MOUNT_NOACL, 0},

{"posix=1", MOUNT_NOPOSIX, 1},

{"posix=0", MOUNT_NOPOSIX, 0}

};

它只能取上面列出的字符串组合。

比如我们定义下面一行数据:

c:\windows /windows/ xpdir user

这样定义之后,我们就可以在bash下面使用

cd /windows

命令了,它将当前路径改为c:\windows

需要注意的是:在fstab没有数据的情况下,cygwin仍然允许通过/cygdrive/c这样的路径访问c盘的内容,其它的盘符同理。

2 参考资料

cygwin关键技术:fork(2009-9-4)

cygwin关键技术:设备模拟(2009-9-4)

cygwin关键技术cygheap(2009-9-2)

cygwin关键技术:tls(2009-8-24)

你可能感兴趣的:(C++,c,windows,C#,bash)