cygwin下的/etc/fstab

本文详细解析了Cygwin中的fstab配置文件的作用及其内部处理机制,介绍了如何通过fstab实现Windows路径与POSIX路径间的映射。

快乐虾

http://blog.youkuaiyun.com/lights_joy/

lights@hb165.com

 

本文适用于

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)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值