Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : : 3 : : #include <errno.h> 4 : : #include <fcntl.h> 5 : : #include <sys/ioctl.h> 6 : : #include <sys/stat.h> 7 : : #include <linux/fs.h> 8 : : 9 : : #include "chattr-util.h" 10 : : #include "fd-util.h" 11 : : #include "macro.h" 12 : : 13 : 72 : int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { 14 : : unsigned old_attr, new_attr; 15 : : struct stat st; 16 : : 17 [ - + ]: 72 : assert(fd >= 0); 18 : : 19 [ - + ]: 72 : if (fstat(fd, &st) < 0) 20 : 0 : return -errno; 21 : : 22 : : /* Explicitly check whether this is a regular file or 23 : : * directory. If it is anything else (such as a device node or 24 : : * fifo), then the ioctl will not hit the file systems but 25 : : * possibly drivers, where the ioctl might have different 26 : : * effects. Notably, DRM is using the same ioctl() number. */ 27 : : 28 [ + + - + ]: 72 : if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) 29 : 0 : return -ENOTTY; 30 : : 31 [ - + # # ]: 72 : if (mask == 0 && !previous) 32 : 0 : return 0; 33 : : 34 [ - + ]: 72 : if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) 35 : 0 : return -errno; 36 : : 37 : 72 : new_attr = (old_attr & ~mask) | (value & mask); 38 [ + + ]: 72 : if (new_attr == old_attr) { 39 [ - + ]: 8 : if (previous) 40 : 0 : *previous = old_attr; 41 : 8 : return 0; 42 : : } 43 : : 44 [ + - ]: 64 : if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) 45 : 64 : return -errno; 46 : : 47 [ # # ]: 0 : if (previous) 48 : 0 : *previous = old_attr; 49 : : 50 : 0 : return 1; 51 : : } 52 : : 53 : 64 : int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous) { 54 : 64 : _cleanup_close_ int fd = -1; 55 : : 56 [ - + ]: 64 : assert(p); 57 : : 58 [ - + ]: 64 : if (mask == 0) 59 : 0 : return 0; 60 : : 61 : 64 : fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); 62 [ - + ]: 64 : if (fd < 0) 63 : 0 : return -errno; 64 : : 65 : 64 : return chattr_fd(fd, value, mask, previous); 66 : : } 67 : : 68 : 0 : int read_attr_fd(int fd, unsigned *ret) { 69 : : struct stat st; 70 : : 71 [ # # ]: 0 : assert(fd >= 0); 72 : : 73 [ # # ]: 0 : if (fstat(fd, &st) < 0) 74 : 0 : return -errno; 75 : : 76 [ # # # # ]: 0 : if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) 77 : 0 : return -ENOTTY; 78 : : 79 [ # # ]: 0 : if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) 80 : 0 : return -errno; 81 : : 82 : 0 : return 0; 83 : : } 84 : : 85 : 0 : int read_attr_path(const char *p, unsigned *ret) { 86 : 0 : _cleanup_close_ int fd = -1; 87 : : 88 [ # # ]: 0 : assert(p); 89 [ # # ]: 0 : assert(ret); 90 : : 91 : 0 : fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); 92 [ # # ]: 0 : if (fd < 0) 93 : 0 : return -errno; 94 : : 95 : 0 : return read_attr_fd(fd, ret); 96 : : }