#5 Linux 时间: atime, mtime, ctime

2015-01-03

Linux 文件的三种时间:

  • atime 访问时间 Access
  • ctime 修改时间 Change, 文件状态变化
  • mtime 修改时间 Modify, 文件内容变化

注意:如果 chmod,chown,mv 等不改变文件内容的操作,ctime 变化,mtime 不变。
但是文件内容变化的时候,ctime 和 mtime 都会变化,文件大小没有变化也是一样。
如果通过充定向的方式改变文件内容(> or >>),atime 不会发生变化。

之前有一个测试,可以参考: 2013/04/07, ls 按时间排序

Linux 并没有创建时间,这是令人费解的,可能是早期文件系统没有这个信息吧。

PS: 关于文件的创建时间,参考:2021-12-12 Linux 文件创建时间

#4 Linux 权限管理总结

2014-02-27

文件类型

  • -, 普通文件
  • l, 链接文件
  • d, 目录
  • c, 字符设备文件
  • b, 块设备文件
  • p, 管道文件
  • s, Socket
  • t, 特殊文件

基础

  • 权限类型:
  • r,读 4
  • w,写 2
  • x,可执行 1
  • 用户类型:
  • user, 文件所有者
  • group, 文件所有组的所有用户
  • other,其他用户

目录的权限

  • r: 列出目录下的文件(ls
  • w: 在目录中,创建、删除、重命名文件或子目录
  • x: 进入目录(cd

示例

touch /tmp/testPerm

chmod 7777 /tmp/testPerm

ll /tmp/testPerm
-rwsrwsrwt 1 markjour markjour 0 2014-02-27 17:41:06 /tmp/testPerm

Linux 权限的两种表示方法:

  • 数字:
  • 字母:
    第一位表示文件类型
    第 2 - 4 位表示文件所有者的权限
    第 5 - 7 位表示文件所有组的权限
    第 8 - 10 位表示其他用户的权限

特殊权限

Linux 中的权限一共用 12 位来表示,除了上面 u g o 各 3 位(rwx)一共 9 位之外,还有 3 位:

  • setuid / suid, 4,显示为 S(显示在所有者权限中的第三位,如果有 x 的话,就显示 s)
  • setgid / sgid,2,显示为 S(显示在所有组权限中的第三位,如果有 x 的话,就显示 s)
  • sticky bit ,1,显示为 T

  • suid, sgid 是用来给文件设置临时提权用的。如果设置, 所有用户都会继承文件所有者或所有组的权限。

  • 如果目录设置了 sgid,那么该目录中新创建的文件和子目录会继承目录的所在组。
  • sticky bit 一般翻译为粘滞位,设置在目录上, 仅允许文件所有者(或 root)才能删除改目录下的文件。
    Linux 或 FreeBSD 都会忽略文件上的 sticky bit。
  suid sgid sbit
文件
目录
$ ls -alh /bin/ | grep rws
-rwsr-sr-x  1 daemon  daemon      55K 2022-04-14 08:23:36 at
-rwsr-xr-x  1 root    root        72K 2022-11-24 20:05:18 chfn
-rwsr-xr-x  1 root    root        44K 2022-11-24 20:05:18 chsh
-rwsr-xr-x  1 root    root        35K 2022-03-23 21:53:14 fusermount3
-rwsr-xr-x  1 root    root        71K 2022-11-24 20:05:18 gpasswd
-rwsr-xr-x  1 root    root        47K 2023-04-07 06:21:06 ksu
-rwsr-xr-x  1 root    root        47K 2022-02-21 09:49:57 mount
-rwsr-xr-x  1 root    root        28K 2022-11-24 20:05:18 newgidmap
-rwsr-xr-x  1 root    root        40K 2022-11-24 20:05:18 newgrp
-rwsr-xr-x  1 root    root        28K 2022-11-24 20:05:18 newuidmap
-rwsr-xr-x  1 root    root        31K 2022-02-07 21:05:06 nvidia-modprobe
-rwsr-xr-x  1 root    root        59K 2022-11-24 20:05:18 passwd
-rwsr-xr-x  1 root    root        31K 2022-02-26 19:11:57 pkexec
-rwsr-xr-x  1 root    root        55K 2022-02-21 09:49:57 su
-rwsr-xr-x  1 root    root       227K 2023-04-04 02:00:44 sudo
-rwsr-xr-x  1 root    root        35K 2022-02-21 09:49:57 umount
$ find /bin/ -type f -perm /4000 -ls

  7342874     36 -rwsr-xr-x   1 root     root        35200 Mar 23  2022 /bin/fusermount3
  7352563     28 -rwsr-xr-x   1 root     root        28136 Nov 24  2022 /bin/newuidmap
  7341794     32 -rwsr-xr-x   1 root     root        30872 Feb 26  2022 /bin/pkexec
  7347918     36 -rwsr-xr-x   1 root     root        35192 Feb 21  2022 /bin/umount
  7347747     48 -rwsr-xr-x   1 root     root        47480 Feb 21  2022 /bin/mount
  7344663     28 -rwsr-xr-x   1 root     root        28136 Nov 24  2022 /bin/newgidmap
  7349993     72 -rwsr-xr-x   1 root     root        72072 Nov 24  2022 /bin/gpasswd
  7350008     60 -rwsr-xr-x   1 root     root        59976 Nov 24  2022 /bin/passwd
  7347439    228 -rwsr-xr-x   1 root     root       232416 Apr  4 02:00 /bin/sudo
  7344105     32 -rwsr-xr-x   1 root     root        30936 Feb  7  2022 /bin/nvidia-modprobe
  7345135     56 -rwsr-xr-x   1 root     root        55672 Feb 21  2022 /bin/su
  7347241     72 -rwsr-xr-x   1 root     root        72712 Nov 24  2022 /bin/chfn
  7352704     40 -rwsr-xr-x   1 root     root        40496 Nov 24  2022 /bin/newgrp
  7347300     44 -rwsr-xr-x   1 root     root        44808 Nov 24  2022 /bin/chsh
  7382902     48 -rwsr-xr-x   1 root     root        47416 Apr  7 06:21 /bin/ksu
  7343017     56 -rwsr-sr-x   1 daemon   daemon      55624 Apr 14  2022 /bin/at

$ find /bin/ -type f -perm /2000 -ls

  7342246     16 -rwxr-sr-x   1 root     root        15504 Jan 12  2022 /bin/dotlock.mailutils
  7347219     72 -rwxr-sr-x   1 root     shadow      72184 Nov 24  2022 /bin/chage
  7346616     24 -rwxr-sr-x   1 root     tty         22912 Feb 21  2022 /bin/write.ul
  7340649    308 -rwxr-sr-x   1 root     plocate    313904 Feb 17  2022 /bin/plocate
  7341420     40 -rwxr-sr-x   1 root     crontab     39568 Mar 23  2022 /bin/crontab
  7349934     24 -rwxr-sr-x   1 root     shadow      23136 Nov 24  2022 /bin/expiry
  7347279     24 -rwxr-sr-x   1 root     tty         22904 Feb 21  2022 /bin/wall
  7345047    288 -rwxr-sr-x   1 root     _ssh       293304 Nov 23  2022 /bin/ssh-agent
  7343017     56 -rwsr-sr-x   1 daemon   daemon      55624 Apr 14  2022 /bin/at

https://en.wikipedia.org/wiki/Setuid
https://en.wikipedia.org/wiki/Sticky_bit
https://web.archive.org/web/20130204053849/http://content.hccfl.edu/pollock/aunix1/filepermissions.htm

操作

  • chown 更改文件所有者和文件所有组
  • chgrp 更改文件所有组
  • chmod 更改权限
chmod 755 filePath
chmod 644 filePath
chmod u+x filePath
chmod g+r filePath
chmod o+w filePath
chmod a+r filePath

#3 MingW 与 Cygwin

2013-12-12

首先 MinGW 和 Cygwin 都可以用来跨平台开发。

MinGW 是 Minimalistic GNU for Windows 的缩写,也就是 Win 版的 GCC。

Cygwin 则是全面模拟了Linux的接口,提供给运行在它上面的的程序使用,并提供了大量现成的软件,更像是一个平台。

相对的 MingW 也有一个叫 MSys(Minimal SYStem)的子项目,主要是提供了一个模拟 Linux 的 Shell 和一些基本的 Linux 工具。因为编译一个大型程序,光靠一个 GCC 是不够的,还需要有 Autoconf 等工具来配置项目,所以一般在 Windows 下编译 ffmpeg 等 Linux 下的大型项目都是通过Msys 来完成的,当然 Msys 只是一个辅助环境,根本的工作还是 MingW 来做的。

基本原理

  1. 修改编译器,让 Window 下的编译器把诸如 fork 的调用翻译成等价的形式,这就是 MingW 的做法.
  2. 修改库,让 Window 提供一个类似 UNIX 提供的库,他们对程序的接口如同 UNIX 一样,而这些库,当然是由 win32 的 API 实现的,这就是 Cygwin 的做法.

用 MingW 和 Cygwin 编译出来的程序的区别

首先 MingW 和 Cygwin 都不能让 Linux 下的程序直接运行在 Windows 上,必需通过源代码重新编译。

现代操作系统包括 Windows 和 Linux 的基本设计概念像进程线程地址空间虚拟内存这些都是大同小异的,之所以二者上的程序不能兼容,主要是它们对这些功能具体实现上的差异,首先是可执行文件的格式,Window 使用 PE 的格式,并且要求以 .EXE 为后缀名。Linux 则使用 Elf。其次操作系统的 API 也不一样,如 Windows 用 CreateProcess() 创建进程,而 Linux 使用 fork()

所以要移植程序必然要在这些地方进行改变,MingW 有专门的 W32api 头文件,来把代码中 Linux 方式的系统调用替换为对应的 Windows 方式。而 Cygwin 则通过 cygwin1.dll 这个文件来实现这种 API 的转换,并模拟一个 Linux 系统调用接口给程序,程序依然以 Linux 的方式调用系统 API,只不过这个 API 在 cygwin1.dll 上,cygwin1.dll 再调用 Windows 对应的实现,来把结果返回给程序。

可以用查看他们编译好的程序的导入表来验证这点。

二者生成的程序都是能在 Windows 上运行的 EXE 文件,显然都是 PE 格式,用一个PE格式查看工具检查一下就能发现,Cygwin 生成的程序依然有 fork() 这样的 Linux 系统调用,但目标库是 cygwin1。而 MingW 生成的程序,则全部使用从 KERNEL32 导出的标准 Windows 系统 API。

这样看来用 MingW 编译的程序性能会高一点,而且也不用带着那个接近两兆的 cygwin1.dll 文件。

但 Cygwin 对 Linux 的模拟比较完整,甚至有一个 Cygwin X 的项目,可以直接用 Cygwin 跑 X。

另外 Cygwin 可以设置 -mno-cygwin 的 flag,来使用 MingW 编译。

而与 Cygwin 更有可比性的 MSys 上的工具也是通过 Cygwin 这种模拟的方式来提供的。

总之这两个项目有千丝万缕的关系,一个不恰当的比方,如果 Mingw 是 MFC,Cygwin 就是 .NET 了。

#2 各种链接文件

2013-04-29

Windows 系统

  • 硬链接 Hard Link
  • 同一分区内的文件
  • 软链接 Soft Link / 符号链接 Symbolic Link
  • 文件或目录都行
  • 可以在任何位置,跨磁盘,跨主机
  • 目标位置不存在也没有关系
  • 连接点 Junction,类似软链接,但是需要是本地路径
  • dir 查看目录时显示不同(<SYMLINK><JUNCTION>

PS:Windows 下创建的快捷方式(.lnk 文件)不属于文件链接,在文件系统中也不是透明的存在,只在 图形界面中有用。

$ mklink /?
创建符号链接。

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      创建目录符号链接。默认为文件
                符号链接。
        /H      创建硬链接而非符号链接。
        /J      创建目录联接。
        Link    指定新的符号链接名称。
        Target  指定新链接引用的路径
                (相对或绝对)。

Linux 系统

只有软链接和硬链接两种,没有 Junction 这种东西混淆视听。

ln -sf src dst  # 创建软链接
ln -Pf src dst  # 创建硬链接
$ ln --help
用法:ln [选项]... [-T] 目标 链接名
 或:ln [选项]... 目标
 或:ln [选项]... 目标... 目录
 或:ln [选项]... -t 目录 目标...
在第一种格式中,创建具有指定<链接名>且指向指定<目标>的链接。
在第二种格式中,在当前目录创建指向<目标>位置的链接。
在第三、四种格式中,在指定<目录>中创建指向指定<目标>的链接。
默认创建硬链接,当使用--symbolic 时创建符号链接。
默认情况下,创建每个目标时不应存在与新链接的名称相同的文件。
创建硬链接时,每个指定的<目标>都必须存在。符号链接可以指向任意的位置;
当链接解析正常时,将其解析为一个相对于其父目录的相对链接。

必选参数对长短选项同时适用。
      --backup[=CONTROL]      为每个已存在的目标文件创建备份文件
  -b                          类似--backup,但不接受任何参数
  -d, -F, --directory         允许超级用户尝试创建指向目录的硬链接
                              (注意:此操作可能因系统限制而失败)
  -f, --force                 强行删除任何已存在的目标文件
  -i, --interactive           删除目标文件前进行确认
  -L, --logical               如目标为符号链接,本次创建链接时将其解引用
  -n, --no-dereference        如果给定<链接名>是一个链接至某目录的符号链接,
                                将其作为普通文件处理
  -P, --physical              创建直接指向符号链接文件的硬链接
  -r, --relative              创建相对于链接位置的符号链接
  -s, --symbolic              创建符号链接而非硬链接
  -S, --suffix=后缀           自行指定备份文件的后缀
  -t, --target-directory=目录  在指定<目录>中创建链接
  -T, --no-target-directory   总是将给定的<链接名>当作普通文件
  -v, --verbose               列出每个链接的文件名称
      --help            显示此帮助信息并退出
      --version         显示版本信息并退出

备份文件的后缀为"~",除非以--suffix 选项或是 SIMPLE_BACKUP_SUFFIX
环境变量指定。版本控制的方式可通过--backup 选项或 VERSION_CONTROL 环境
变量来选择。以下是可用的变量值:

  none, off       不进行备份(即使使用了--backup 选项)
  numbered, t     备份文件加上数字进行排序
  existing, nil   若有数字的备份文件已经存在则使用数字,否则使用普通方式备份
  simple, never   永远使用普通方式备份

使用 -s 选项会忽略 -L 和 -P。
否则当<目标>为一个符号链接(默认为 -P)时,会由最后一个指定的选项来控制行为。

GNU coreutils 在线帮助:<https://www.gnu.org/software/coreutils/>
请向 <http://translationproject.org/team/zh_CN.html> 报告任何翻译错误
完整文档 <https://www.gnu.org/software/coreutils/ln>
或者在本地使用:info '(coreutils) ln invocation'

参考资料与拓展阅读

#1 ls 按时间排序

2013-04-07
## list, sort by name

# display mtime (默认)
ls -l
# display ctime
ls -lc
ls -l --time=ctime # OR status
# display atime
ls -lu
ls -l --time=atime # OR access, use
# display birth time
ls -l --time=birth # OR creation

## list, sort by time

# sort by mtime
ls -lt
ls -lt --time=mtime
# sort by ctime
ls -ltc
ls -lt --time=ctime
# sort by atime
ls -ltu
ls -lt --time=atime
# sort by birth time
ls -lt --time=birth

助记:

-l # list, sort by name
-t # sort by time
-c # use ctime
-u # use atime
--time=ctime/atime/birth
# 默认时间是 mtime

小实验

# cat /tmp/test.sh
set -xe

rm -f /tmp/a.log

date +%T
touch /tmp/a.log        # brtime, birth time
sleep 1

date +%T
echo "hello world" > /tmp/a.log # mtime, modify time
sleep 1

date +%T
cat /tmp/a.log          # atime, access time
sleep 1

date +%T
chmod 666 /tmp/a.log    # ctime, change time
sleep 1

# date +%T
# echo "nihao" >> /tmp/a.log # mtime, modify time
# sleep 1

stat /tmp/a.log

PS: 修改内容的时候也会更改 ctime