1/* vi: set sw=4 ts=4: */ 2/* 3 * See README for additional information 4 * 5 * This file can be redistributed under the terms of the GNU Library General 6 * Public License 7 */ 8 9#include "libbb.h" 10#include "e2fs_lib.h" 11 12#define HAVE_EXT2_IOCTLS 1 13 14#if INT_MAX == LONG_MAX 15#define IF_LONG_IS_SAME(...) __VA_ARGS__ 16#define IF_LONG_IS_WIDER(...) 17#else 18#define IF_LONG_IS_SAME(...) 19#define IF_LONG_IS_WIDER(...) __VA_ARGS__ 20#endif 21 22static void close_silently(int fd) 23{ 24 int e = errno; 25 close(fd); 26 errno = e; 27} 28 29 30/* Iterate a function on each entry of a directory */ 31int iterate_on_dir(const char *dir_name, 32 int (*func)(const char *, struct dirent *, void *), 33 void * private) 34{ 35 DIR *dir; 36 struct dirent *de, *dep; 37 int max_len, len; 38 39 max_len = PATH_MAX + sizeof(struct dirent); 40 de = xmalloc(max_len+1); 41 memset(de, 0, max_len+1); 42 43 dir = opendir(dir_name); 44 if (dir == NULL) { 45 free(de); 46 return -1; 47 } 48 while ((dep = readdir(dir))) { 49 len = sizeof(struct dirent); 50 if (len < dep->d_reclen) 51 len = dep->d_reclen; 52 if (len > max_len) 53 len = max_len; 54 memcpy(de, dep, len); 55 func(dir_name, de, private); 56 } 57 closedir(dir); 58 free(de); 59 return 0; 60} 61 62 63/* Get/set a file version on an ext2 file system */ 64int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version) 65{ 66#if HAVE_EXT2_IOCTLS 67 int fd, r; 68 IF_LONG_IS_WIDER(int ver;) 69 70 fd = open(name, O_NONBLOCK); 71 if (fd == -1) 72 return -1; 73 if (!get_version) { 74 IF_LONG_IS_WIDER( 75 ver = (int) set_version; 76 r = ioctl(fd, EXT2_IOC_SETVERSION, &ver); 77 ) 78 IF_LONG_IS_SAME( 79 r = ioctl(fd, EXT2_IOC_SETVERSION, (void*)&set_version); 80 ) 81 } else { 82 IF_LONG_IS_WIDER( 83 r = ioctl(fd, EXT2_IOC_GETVERSION, &ver); 84 *get_version = ver; 85 ) 86 IF_LONG_IS_SAME( 87 r = ioctl(fd, EXT2_IOC_GETVERSION, (void*)get_version); 88 ) 89 } 90 close_silently(fd); 91 return r; 92#else /* ! HAVE_EXT2_IOCTLS */ 93 errno = EOPNOTSUPP; 94 return -1; 95#endif /* ! HAVE_EXT2_IOCTLS */ 96} 97 98 99/* Get/set a file flags on an ext2 file system */ 100int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags) 101{ 102#if HAVE_EXT2_IOCTLS 103 struct stat buf; 104 int fd, r; 105 IF_LONG_IS_WIDER(int f;) 106 107 if (stat(name, &buf) == 0 /* stat is ok */ 108 && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) 109 ) { 110 goto notsupp; 111 } 112 fd = open(name, O_NONBLOCK); /* neither read nor write asked for */ 113 if (fd == -1) 114 return -1; 115 116 if (!get_flags) { 117 IF_LONG_IS_WIDER( 118 f = (int) set_flags; 119 r = ioctl(fd, EXT2_IOC_SETFLAGS, &f); 120 ) 121 IF_LONG_IS_SAME( 122 r = ioctl(fd, EXT2_IOC_SETFLAGS, (void*)&set_flags); 123 ) 124 } else { 125 IF_LONG_IS_WIDER( 126 r = ioctl(fd, EXT2_IOC_GETFLAGS, &f); 127 *get_flags = f; 128 ) 129 IF_LONG_IS_SAME( 130 r = ioctl(fd, EXT2_IOC_GETFLAGS, (void*)get_flags); 131 ) 132 } 133 134 close_silently(fd); 135 return r; 136 notsupp: 137#endif /* HAVE_EXT2_IOCTLS */ 138 errno = EOPNOTSUPP; 139 return -1; 140} 141 142 143/* Print file attributes on an ext2 file system */ 144struct flags_name { 145 unsigned long flag; 146 char short_name; 147 const char *long_name; 148}; 149 150/* TODO: apart from I and (disabled) COMPRESSION flags, this 151 * is a duplicate of a table from chattr. Merge? */ 152static const struct flags_name flags_array[] = { 153 { EXT2_SECRM_FL, 's', "Secure_Deletion" }, 154 { EXT2_UNRM_FL, 'u' , "Undelete" }, 155 { EXT2_SYNC_FL, 'S', "Synchronous_Updates" }, 156 { EXT2_DIRSYNC_FL, 'D', "Synchronous_Directory_Updates" }, 157 { EXT2_IMMUTABLE_FL, 'i', "Immutable" }, 158 { EXT2_APPEND_FL, 'a', "Append_Only" }, 159 { EXT2_NODUMP_FL, 'd', "No_Dump" }, 160 { EXT2_NOATIME_FL, 'A', "No_Atime" }, 161 { EXT2_COMPR_FL, 'c', "Compression_Requested" }, 162#ifdef ENABLE_COMPRESSION 163 { EXT2_COMPRBLK_FL, 'B', "Compressed_File" }, 164 { EXT2_DIRTY_FL, 'Z', "Compressed_Dirty_File" }, 165 { EXT2_NOCOMPR_FL, 'X', "Compression_Raw_Access" }, 166 { EXT2_ECOMPR_FL, 'E', "Compression_Error" }, 167#endif 168 { EXT3_JOURNAL_DATA_FL, 'j', "Journaled_Data" }, 169 { EXT2_INDEX_FL, 'I', "Indexed_directory" }, 170 { EXT2_NOTAIL_FL, 't', "No_Tailmerging" }, 171 { EXT2_TOPDIR_FL, 'T', "Top_of_Directory_Hierarchies" }, 172 { 0, '\0', NULL } 173}; 174 175void print_flags(FILE *f, unsigned long flags, unsigned options) 176{ 177 const struct flags_name *fp; 178 179 if (options & PFOPT_LONG) { 180 int first = 1; 181 for (fp = flags_array; fp->short_name; fp++) { 182 if (flags & fp->flag) { 183 if (!first) 184 fputs(", ", f); 185 fputs(fp->long_name, f); 186 first = 0; 187 } 188 } 189 if (first) 190 fputs("---", f); 191 } else { 192 for (fp = flags_array; fp->short_name; fp++) { 193 char c = '-'; 194 if (flags & fp->flag) 195 c = fp->short_name; 196 fputc(c, f); 197 } 198 } 199} 200