如何在SBCL中获取文件的持有者

因为想要给博客的文章增加作者的信息,因此最近琢磨了一下怎么获取文件的owner的名字。

虽然说博客的文章都是我一个人写的,作者也理所当然的都是我自己,但好歹打算将cl-github-page做成一个可以供别人使用的工具,自然不能把作者的名字也写死在代码中,必然是要寻找一些方法来获取这类信息的。一个很自然的想法,起始就是用当前登录系统的用户的名字,因为很多情况下一台电脑就是属于一个人的。这种方式的话很容易就可以做到了,比如通过环境变量USER来获取当前登录的用户名。用Common Lisp的Osicat库可以实现

(osicat:environment-variable "USER")

虽然够用了,但这始终不是文件的作者,而是这个系统的使用者的名字,就算覆盖度很高,直接拿来用还是显得有一些别扭。为了可以知晓到底应该怎么获取文件的持有者的信息,想到了平时经常使用的ls命令。ls命令有一个--author选项,可以输出文件的作者的名字,效果如下

$ ls --author -dl /tmp/
drwxrwxrwt 13 root root root 12288  8月 23 19:18 /tmp/

好吧,起始我根本不知道哪一列才是这个文件的作者,不过好歹我通过man文档知道了ls命令可以获取文件的作者,那么接下来的事情就简单了,只要查看ls的源代码即可。使用apt-get source下载到了coreutils的源代码之后,在src目录中很容易就看到了ls.c文件,ls命令的奥秘就在其中了。在没有多少耐心地扫视了几眼之后,发现有一个叫做st_author的变量很可疑,但貌似没有看出是在哪一个位置给这个成员变量赋值的,于是退出到命令行,用下面这条命令在src目录下乱搜索了一番

find . -name '*.c' -exec grep -Hn --color=auto 'st_author' {} \;

第一条搜索结果就是一个很可疑的家伙,原来st_author是一个宏,实际上会被展开为st_uid这么个东西。这个是啥?其实就是struct stat这个类型中的一个成员变量。struct stat又是个啥?自己看一下man文档把,请使用命令:man 2 stat

现在终于知道了,原来ls也没什么神秘的,并且系统也没有直接提供获取文件的持有者的名字的函数。正经的步骤,应该就是先用stat获取到文件的持有者的用户ID,然后再根据用户ID调用其它的函数来获得用户的名字。至此,终于可以在SBCL中写出差不多的代码了。好了,怎么做呢?首先要找到与stat(2)对应的函数,这个函数不属于Common Lisp标准的一部分(其实这里是我乱写的,但我有足够的自信),而是由SBCL提供的一个隶属于implementation的功能,这个函数叫做sb-posix:stat。而用来取出用户ID的函数叫做sb-posix:stat-uid。现在我们还需要一个通过用户ID取到用户名的功能,在哪呢?就在刚才用来获取环境变量的库Osicat里,叫做Osicat:user-info。至此,东西已经准备齐全,施法吧!

(let* ((stat (sb-posix:stat #P"/tmp/"))
       (uid (sb-posix:stat-uid stat)))
  (cdr (assoc :name (osicat:user-info uid))))

在我的机器上,上述代码的运行结果为"root",将其中的"/tmp/"替换成其它的文件路径就可以获得其它文件的持有者的名字啦。当然啦,前提是你用的是SBCL这个实现。

全文完