Путь: Toys/Other, команды версии: Ver.4 Ver.9 Комментарии в файле lsattr.c : Команд: 2 lsattr
chattr
Исходный текст в файле lsattr.c #define FOR_lsattr #include "toys.h" #include <linux/fs.h> GLOBALS( long v, p; unsigned add, rm, set; // !add and !rm tell us whether they were used, but `chattr =` is meaningful. int have_set; ) // Added more recently than the 7 year support horizon. TODO: remove #ifndef FS_INLINE_DATA_FL #define FS_INLINE_DATA_FL 0x10000000 // commit 68ce7bfcd995a 2016-01-08 #endif #ifndef FS_PROJINHERIT_FL #define FS_PROJINHERIT_FL 0x20000000 // commit 8b4953e13f4c5 2015-10-17 #endif #ifndef FS_CASEFOLD_FL #define FS_CASEFOLD_FL 0x40000000 // commit 71e90b4654a92 2019-07-23 #endif #ifndef FS_VERITY_FL #define FS_VERITY_FL 0x00100000 // commit fe9918d3b228b 2019-07-22 #endif #ifndef FS_IOC_FSGETXATTR // commit 334e580a6f97e 2016-01-04 struct fsxattr { unsigned fsx_xflags, fsx_extsize, fsx_nextents, fsx_projid, fsx_cowextsize; char fsx_pad[8]; }; #define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) #define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) #endif static struct ext2_attr { char *name; unsigned flag; char opt; } e2attrs[] = { // Do not sort! These are in the order that lsattr outputs them. {"Secure_Deletion", FS_SECRM_FL, 's'}, {"Undelete", FS_UNRM_FL, 'u'}, {"Synchronous_Updates", FS_SYNC_FL, 'S'}, {"Synchronous_Directory_Updates", FS_DIRSYNC_FL, 'D'}, {"Immutable", FS_IMMUTABLE_FL, 'i'}, {"Append_Only", FS_APPEND_FL, 'a'}, {"No_Dump", FS_NODUMP_FL, 'd'}, {"No_Atime", FS_NOATIME_FL, 'A'}, {"Compression_Requested", FS_COMPR_FL, 'c'}, // FS_ENCRYPT_FL added to linux 4.5 march 2016, +y7 = 2023 {"Encrypted", 0x800, 'E'}, {"Journaled_Data", FS_JOURNAL_DATA_FL, 'j'}, {"Indexed_directory", FS_INDEX_FL, 'I'}, {"No_Tailmerging", FS_NOTAIL_FL, 't'}, {"Top_of_Directory_Hierarchies", FS_TOPDIR_FL, 'T'}, {"Extents", FS_EXTENT_FL, 'e'}, {"No_COW", FS_NOCOW_FL, 'C'}, {"Casefold", FS_CASEFOLD_FL, 'F'}, {"Inline_Data", FS_INLINE_DATA_FL, 'N'}, {"Project_Hierarchy", FS_PROJINHERIT_FL, 'P'}, {"Verity", FS_VERITY_FL, 'V'}, {NULL, 0, 0}, }; // Get file flags on a Linux second extended file system. static int ext2_getflag(int fd, struct stat *sb, unsigned *flag) { if(!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode)) { errno = EOPNOTSUPP; return -1; } return (ioctl(fd, FS_IOC_GETFLAGS, (void*)flag)); } static char *attrstr(unsigned attrs, int full) { struct ext2_attr *a = e2attrs; char *s = toybuf; for (; a->name; a++) if (attrs & a->flag) *s++ = a->opt; else if (full) *s++ = '-'; *s = 0; return toybuf; } static void print_file_attr(char *path) { unsigned flag = 0, version = 0; int fd = -1; struct stat sb; if (!stat(path, &sb) && !S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode)) { errno = EOPNOTSUPP; goto error; } if (-1 == (fd=open(path, O_RDONLY | O_NONBLOCK))) goto error; if (FLAG(p)) { struct fsxattr fsx; if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx)) goto error; xprintf("%5u ", fsx.fsx_projid); } if (FLAG(v)) { if (ioctl(fd, FS_IOC_GETVERSION, (void*)&version) < 0) goto error; xprintf("%-10u ", version); } if (ext2_getflag(fd, &sb, &flag) < 0) perror_msg("reading flags '%s'", path); else { struct ext2_attr *ptr = e2attrs; if (FLAG(l)) { int name_found = 0; xprintf("%-50s ", path); for (; ptr->name; ptr++) { if (flag & ptr->flag) { if (name_found) xprintf(", "); //for formatting. xprintf("%s", ptr->name); name_found = 1; } } if (!name_found) xprintf("---"); xputc('\n'); } else xprintf("%s %s\n", attrstr(flag, 1), path); } path = 0; error: xclose(fd); if (path) perror_msg("reading '%s'", path); } // Get directory information. static int retell_dir(struct dirtree *root) { char *fpath = NULL; if (root->again) { xputc('\n'); return 0; } if (S_ISDIR(root->st.st_mode) && !root->parent) return (DIRTREE_RECURSE | DIRTREE_COMEAGAIN); fpath = dirtree_path(root, NULL); //Special case: with '-a' option and '.'/'..' also included in printing list. if ((root->name[0] != '.') || FLAG(a)) { print_file_attr(fpath); if (S_ISDIR(root->st.st_mode) && FLAG(R) && dirtree_notdotdot(root)) { xprintf("\n%s:\n", fpath); free(fpath); return (DIRTREE_RECURSE | DIRTREE_COMEAGAIN); } } free(fpath); return 0; } void lsattr_main(void) { if (!*toys.optargs) dirtree_read(".", retell_dir); else for (; *toys.optargs; toys.optargs++) { struct stat sb; if (lstat(*toys.optargs, &sb)) perror_msg("stat '%s'", *toys.optargs); else if (S_ISDIR(sb.st_mode) && !FLAG(d)) dirtree_read(*toys.optargs, retell_dir); else print_file_attr(*toys.optargs);// to handle "./Filename" or "./Dir" } } // Switch gears from lsattr to chattr. #define FOR_chattr #include "generated/flags.h" // Set file flags on a Linux second extended file system. static inline int ext2_setflag(int fd, struct stat *sb, unsigned flag) { if (!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode)) { errno = EOPNOTSUPP; return -1; } return (ioctl(fd, FS_IOC_SETFLAGS, (void*)&flag)); } static unsigned get_flag_val(char ch) { struct ext2_attr *ptr = e2attrs; for (; ptr->name; ptr++) if (ptr->opt == ch) return ptr->flag; help_exit("bad '%c'", ch); } // Parse command line argument and fill the chattr structure. static void parse_cmdline_arg(char ***argv) { char *arg = **argv, *ptr; while (arg) { switch (arg[0]) { case '-': for (ptr = ++arg; *ptr; ptr++) TT.rm |= get_flag_val(*ptr); break; case '+': for (ptr = ++arg; *ptr; ptr++) TT.add |= get_flag_val(*ptr); break; case '=': TT.have_set = 1; for (ptr = ++arg; *ptr; ptr++) TT.set |= get_flag_val(*ptr); break; default: return; } arg = *(*argv += 1); } } // Update attribute of given file. static int update_attr(struct dirtree *root) { char *fpath = NULL; int vv = TT.v, fd; if (!dirtree_notdotdot(root)) return 0; /* * if file is a link and recursive is set or file is not regular+link+dir * (like fifo or dev file) then escape the file. */ if ((S_ISLNK(root->st.st_mode) && FLAG(R)) || (!S_ISREG(root->st.st_mode) && !S_ISLNK(root->st.st_mode) && !S_ISDIR(root->st.st_mode))) return 0; fpath = dirtree_path(root, NULL); if (-1 == (fd=open(fpath, O_RDONLY | O_NONBLOCK))) { free(fpath); return DIRTREE_ABORT; } // Any potential flag changes? if (TT.have_set | TT.add | TT.rm) { unsigned orig, new; // Read current flags. if (ext2_getflag(fd, &(root->st), &orig) < 0) { perror_msg("read flags of '%s'", fpath); free(fpath); xclose(fd); return DIRTREE_ABORT; } // Apply the requested changes. if (TT.have_set) new = TT.set; // '='. else { // '-' and/or '+'. new = orig; new &= ~(TT.rm); new |= TT.add; if (!S_ISDIR(root->st.st_mode)) new &= ~FS_DIRSYNC_FL; } // Write them back if there was any change. if (orig != new && ext2_setflag(fd, &(root->st), new)<0) perror_msg("%s: setting flags to =%s failed", fpath, attrstr(new, 0)); } // (FS_IOC_SETVERSION works all the way back to 2.6, but FS_IOC_FSSETXATTR // isn't available until 4.5.) if (FLAG(v) && (ioctl(fd, FS_IOC_SETVERSION, &vv)<0)) perror_msg("%s: setting version to %d failed", fpath, vv); if (FLAG(p)) { struct fsxattr fsx; int fail = ioctl(fd, FS_IOC_FSGETXATTR, &fsx); fsx.fsx_projid = TT.p; if (fail || ioctl(fd, FS_IOC_FSSETXATTR, &fsx)) perror_msg("%s: setting projid to %u failed", fpath, fsx.fsx_projid); } free(fpath); xclose(fd); return (FLAG(R) && S_ISDIR(root->st.st_mode)) ? DIRTREE_RECURSE : 0; } void chattr_main(void) { char **argv = toys.optargs; parse_cmdline_arg(&argv); if (TT.p < 0 || TT.p > UINT_MAX) error_exit("bad projid %lu", TT.p); if (TT.v < 0 || TT.v > UINT_MAX) error_exit("bad version %ld", TT.v); if (!*argv) help_exit("no file"); if (TT.have_set && (TT.add || TT.rm)) error_exit("no '=' with '-' or '+'"); if (TT.rm & TT.add) error_exit("set/unset same flag"); if (!(TT.add || TT.rm || TT.have_set || FLAG(p) || FLAG(v))) error_exit("need '-p', '-v', '=', '-', or '+'"); for (; *argv; argv++) dirtree_read(*argv, update_attr); } |