简体   繁体   中英

How do I chattr +i an open file descriptor in C?

I want to make a binary that does the equivalent to chattr +i (immutable file) in C. I have attempted with ioctl() and had no success with it. If possible I would like it to be done without the need to include any additional libraries that are not installed/defined in a standard installation.

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

int main()
{
    FILE *fp;
    char shovel[16] = "I have a shovel!";
    fp = fopen("shovel.txt", "w+");
    fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
    int immutable = FS_IMMUTABLE_FL;
    if(ioctl(fileno(fp), FS_IOC_SETFLAGS, &immutable) < 0)
        perror("ioctl(2) error");
    fclose(fp);
    return 0;
}

perror returns "ioctl(2) error: Operation not supported" when ran as root with global rwx on the file.

I have tested that chattr +i works on the command line. The file becomes immutable as expected.

Also the question marked as duplicate is my question on an account I no longer have access to. It's linked to one of many of my google accounts I created.

The script was tested on a friends server last night after my vps went down for maintenance. The feedback I gave on that thread was based on feedback from the friend over skype. What you see above is the results of my own testing on my own server.

Not a duplicate, the original was reporting "Bad Address"

-bash-3.2# cat /proc/mounts
/dev/simfs / simfs rw,relatime,usrquota,grpquota 0 0
proc /proc proc rw,relatime 0 0
sysfs /sys sysfs rw,relatime 0 0
none /dev tmpfs rw,relatime,mode=755 0 0
none /dev/pts devpts rw,relatime,gid=5,mode=620,ptmxmode=000 0 0
none /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0

-bash-3.2# rm shovel.txt
-bash-3.2# ./1
ioctl(2) error: Operation not supported
-bash-3.2# lsattr shovel.txt
------------- shovel.txt
-bash-3.2#

The chattr command itself applies file attribute changes via a very similar call to the one presented in the question:

r = ioctl (fd, EXT2_IOC_SETFLAGS, &f);

where fd is an open file descriptor of type int and f is a flag bitmask of type int . Its behavior differs in the following ways:

  • It obtains the value of the flag bit via the macro EXT2_IMMUTABLE_FLAG . I'm uncertain whether that expands to the same value that FS_IMMUTABLE_FLAG does (though I would be surprised if it didn't).
  • It opens the target file descriptor directly via open() , with open flags O_RDONLY|O_NONBLOCK|O_LARGEFILE (or without O_LARGEFILE if that's not defined).
  • It closes the file descriptor afterward via close()

(Based on e2fsprogs-1.42.12, misc/chattr.c and lib/e2p/fsetflags.c .)

That's drawn from a pretty recent version of e2fsprogs, yet the files involved do not appear to have changed in a very long time, so I'm pretty confident that the same source is applicable to your environment. If the chattr program works for you, then that's the code by which it does so. You should be able to do the same.

Update:

One other difference between chattr and the code in the question: chattr +i merges the immutable flag with any flags already assigned to the file, as obtained via ...

r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);

... and then sets the resulting flag set. In case it matters, it performs this operation on a different file descriptor than the one on which it sets the flags, but one that it opens the same way.

I guess it's possible that your code is inadvertently trying to clear a flag that the driver will not permit you to clear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM