Start 1.33.0 development cycle
[oweals/busybox.git] / e2fsprogs / e2fs_lib.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * See README for additional information
4  *
5  * Licensed under GPLv2, see file LICENSE in this source tree.
6  */
7
8 #include "libbb.h"
9 #include "e2fs_lib.h"
10
11 #define HAVE_EXT2_IOCTLS 1
12
13 #if INT_MAX == LONG_MAX
14 #define IF_LONG_IS_SAME(...) __VA_ARGS__
15 #define IF_LONG_IS_WIDER(...)
16 #else
17 #define IF_LONG_IS_SAME(...)
18 #define IF_LONG_IS_WIDER(...) __VA_ARGS__
19 #endif
20
21 static void close_silently(int fd)
22 {
23         int e = errno;
24         close(fd);
25         errno = e;
26 }
27
28
29 /* Iterate a function on each entry of a directory */
30 int iterate_on_dir(const char *dir_name,
31                 int FAST_FUNC (*func)(const char *, struct dirent *, void *),
32                 void *private)
33 {
34         DIR *dir;
35         struct dirent *de;
36
37         dir = opendir(dir_name);
38         if (dir == NULL) {
39                 return -1;
40         }
41         while ((de = readdir(dir)) != NULL) {
42                 func(dir_name, de, private);
43         }
44         closedir(dir);
45         return 0;
46 }
47
48
49 /* Get/set a file version on an ext2 file system */
50 int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version)
51 {
52 #if HAVE_EXT2_IOCTLS
53         int fd, r;
54         IF_LONG_IS_WIDER(int ver;)
55
56         fd = open(name, O_RDONLY | O_NONBLOCK);
57         if (fd == -1)
58                 return -1;
59         if (!get_version) {
60                 IF_LONG_IS_WIDER(
61                         ver = (int) set_version;
62                         r = ioctl(fd, EXT2_IOC_SETVERSION, &ver);
63                 )
64                 IF_LONG_IS_SAME(
65                         r = ioctl(fd, EXT2_IOC_SETVERSION, (void*)&set_version);
66                 )
67         } else {
68                 IF_LONG_IS_WIDER(
69                         r = ioctl(fd, EXT2_IOC_GETVERSION, &ver);
70                         *get_version = ver;
71                 )
72                 IF_LONG_IS_SAME(
73                         r = ioctl(fd, EXT2_IOC_GETVERSION, (void*)get_version);
74                 )
75         }
76         close_silently(fd);
77         return r;
78 #else /* ! HAVE_EXT2_IOCTLS */
79         errno = EOPNOTSUPP;
80         return -1;
81 #endif /* ! HAVE_EXT2_IOCTLS */
82 }
83
84
85 /* Get/set a file flags on an ext2 file system */
86 int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags)
87 {
88 #if HAVE_EXT2_IOCTLS
89         struct stat buf;
90         int fd, r;
91         IF_LONG_IS_WIDER(int f;)
92
93         if (stat(name, &buf) == 0 /* stat is ok */
94          && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)
95         ) {
96                 goto notsupp;
97         }
98         fd = open(name, O_RDONLY | O_NONBLOCK); /* neither read nor write asked for */
99         if (fd == -1)
100                 return -1;
101
102         if (!get_flags) {
103                 IF_LONG_IS_WIDER(
104                         f = (int) set_flags;
105                         r = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
106                 )
107                 IF_LONG_IS_SAME(
108                         r = ioctl(fd, EXT2_IOC_SETFLAGS, (void*)&set_flags);
109                 )
110         } else {
111                 IF_LONG_IS_WIDER(
112                         r = ioctl(fd, EXT2_IOC_GETFLAGS, &f);
113                         *get_flags = f;
114                 )
115                 IF_LONG_IS_SAME(
116                         r = ioctl(fd, EXT2_IOC_GETFLAGS, (void*)get_flags);
117                 )
118         }
119
120         close_silently(fd);
121         return r;
122  notsupp:
123 #endif /* HAVE_EXT2_IOCTLS */
124         errno = EOPNOTSUPP;
125         return -1;
126 }
127
128
129 /* Print file attributes on an ext2 file system */
130 const uint32_t e2attr_flags_value[] = {
131 #ifdef ENABLE_COMPRESSION
132         EXT2_COMPRBLK_FL,
133         EXT2_DIRTY_FL,
134         EXT2_NOCOMPR_FL,
135         EXT2_ECOMPR_FL,
136 #endif
137         EXT2_INDEX_FL,
138         EXT2_SECRM_FL,
139         EXT2_UNRM_FL,
140         EXT2_SYNC_FL,
141         EXT2_DIRSYNC_FL,
142         EXT2_IMMUTABLE_FL,
143         EXT2_APPEND_FL,
144         EXT2_NODUMP_FL,
145         EXT2_NOATIME_FL,
146         EXT2_COMPR_FL,
147         EXT3_JOURNAL_DATA_FL,
148         EXT2_NOTAIL_FL,
149         EXT2_TOPDIR_FL
150 };
151
152 const char e2attr_flags_sname[] ALIGN1 =
153 #ifdef ENABLE_COMPRESSION
154         "BZXE"
155 #endif
156         "I"
157         "suSDiadAcjtT";
158
159 static const char e2attr_flags_lname[] ALIGN1 =
160 #ifdef ENABLE_COMPRESSION
161         "Compressed_File" "\0"
162         "Compressed_Dirty_File" "\0"
163         "Compression_Raw_Access" "\0"
164         "Compression_Error" "\0"
165 #endif
166         "Indexed_directory" "\0"
167         "Secure_Deletion" "\0"
168         "Undelete" "\0"
169         "Synchronous_Updates" "\0"
170         "Synchronous_Directory_Updates" "\0"
171         "Immutable" "\0"
172         "Append_Only" "\0"
173         "No_Dump" "\0"
174         "No_Atime" "\0"
175         "Compression_Requested" "\0"
176         "Journaled_Data" "\0"
177         "No_Tailmerging" "\0"
178         "Top_of_Directory_Hierarchies" "\0"
179         /* Another trailing NUL is added by compiler */;
180
181 void print_e2flags(FILE *f, unsigned long flags, unsigned options)
182 {
183         const uint32_t *fv;
184         const char *fn;
185
186         fv = e2attr_flags_value;
187         if (options & PFOPT_LONG) {
188                 int first = 1;
189                 fn = e2attr_flags_lname;
190                 do {
191                         if (flags & *fv) {
192                                 if (!first)
193                                         fputs(", ", f);
194                                 fputs(fn, f);
195                                 first = 0;
196                         }
197                         fv++;
198                         fn += strlen(fn) + 1;
199                 } while (*fn);
200                 if (first)
201                         fputs("---", f);
202         } else {
203                 fn = e2attr_flags_sname;
204                 do  {
205                         char c = '-';
206                         if (flags & *fv)
207                                 c = *fn;
208                         fputc(c, f);
209                         fv++;
210                         fn++;
211                 } while (*fn);
212         }
213 }