Shinmera / file-attributes

Access to common file attributes (uid, gid, permissions, ctime, mtime, atime)
https://shinmera.github.io/file-attributes
zlib License
13 stars 2 forks source link

incorrect inode attribute decoding on unix/linux #12

Open dangerdyke opened 1 month ago

dangerdyke commented 1 month ago

The way decode-file-attributes decodes inode attributes for the linux and unix backends is wrong.

for example, i can make a symbolic link, and confirm that it is indeed a symbolic link, like so:

sparrows@vriska:~> echo "hello world" > test.txt
sparrows@vriska:~> ln -s ~/test.txt ~/test-link.txt
sparrows@vriska:~> stat test-link.txt 
  File: test-link.txt -> /home/sparrows/test.txt
  Size: 23          Blocks: 0          IO Block: 4096   symbolic link
Device: 254,0   Inode: 24919398    Links: 1
Access: (0777/lrwxrwxrwx)  Uid: ( 1000/sparrows)   Gid: ( 1000/sparrows)
Access: 2024-06-04 13:34:04.471655266 -0400
Modify: 2024-06-04 13:34:04.471655266 -0400
Change: 2024-06-04 13:34:04.471655266 -0400
 Birth: 2024-06-04 13:34:04.471655266 -0400
sparrows@vriska:~> file test-link.txt 
test-link.txt: symbolic link to /home/sparrows/test.txt

But if I look at the decoded attributes of the created link, the returned plist says it is a normal file, rather then a link. Furthermore, the permissions are wrong; CLI stat shows 0777, yet the plist indicates equivalent to 0644 (the same as the file the link points to)

FILE-ATTRIBUTES> (decode-attributes (attributes #p"~/test-link.txt"))
(:OTHER-EXECUTE NIL :OTHER-WRITE NIL :OTHER-READ T :GROUP-EXECUTE NIL
 :GROUP-WRITE NIL :GROUP-READ T :OWNER-EXECUTE NIL :OWNER-WRITE T :OWNER-READ T
 :STICKY NIL :SET-GROUP NIL :SET-USER NIL :FIFO NIL :DEVICE NIL :DIRECTORY NIL
 :NORMAL T :LINK NIL :SOCKET NIL)

The issue with the inode type is caused by simplistic assumptions about unix file mode bitfields: rather then being a single bit, the type enumeration is represented by matching a number of different 4-bit integer constants. From the linux manpage for inode (masks in octal):

The following mask values are defined for the file type:
   S_IFMT    0170000   bit mask for the file type bit field

   S_IFSO`   0140000   socket
   S_IFLN    0120000   symbolic link
   S_IFRE    0100000   regular file
   S_IFBL    0060000   block device
   S_IFDI    0040000   directory
   S_IFCH    0020000   character device
   S_IFIF    0010000   FIFO

This should be a pretty simple fix, I can make a PR for it.

The permissions issue may require some more investigation on my part. I suspect it may have to do with how pathnames of symlinks are expanded in the lisp code.

dangerdyke commented 1 month ago

A further discovery regarding the latter problem:

It turns out in my above example, the attributes function was indeed expanding the symlink and stating the file it points to, meaning that the filetype decoding issue was actually not the cause of the filetype being listed as normal. However, breaking the symlink causes the library to stat the intended inode. This causes the permission bits to be decoded correctly, but the detected filetype to be even more incorrect: the filetype was decoded as being both a normal file and a block device. This makes sense since the filetype enumeration for symlinks is 0b1010..., which would flag 2 different attributes using the internal decode-bitfield function