iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / util / file.h
blobdf985aa4e0d17dea4bb94ca327f26438a210400e
2 #ifndef EL__UTIL_FILE_H
3 #define EL__UTIL_FILE_H
5 #include <stdio.h>
6 #include <sys/stat.h>
7 #include "util/conv.h"
8 #include "util/string.h"
10 /** Data read about an entry in a directory.
11 * The strings pointed to by this structure are in the system
12 * charset (i.e. LC_CTYPE) and must be freed with mem_free(). */
13 struct directory_entry {
14 /** The various attribute info collected with the @c stat_* functions. */
15 unsigned char *attrib;
17 /** The full path of the dir entry. */
18 unsigned char *name;
21 /** First information such as permissions is gathered for each directory entry.
22 * All entries are then sorted. */
23 struct directory_entry *
24 get_directory_entries(unsigned char *dirname, int get_hidden_files);
26 int file_exists(const unsigned char *filename);
27 int file_can_read(const unsigned char *filename);
28 int file_is_dir(const unsigned char *filename);
30 /** Strips all directory stuff from @a filename and returns the
31 * position of where the actual filename starts */
32 unsigned char *get_filename_position(unsigned char *filename);
34 /** Tilde is only expanded for the current users homedir (~/).
35 * The returned file name is allocated. */
36 unsigned char *expand_tilde(unsigned char *filename);
38 /*! @brief Generate a unique file name by trial and error based on the
39 * @a fileprefix by adding suffix counter (e.g. '.42').
41 * The returned file name is allocated if @a fileprefix is not unique. */
42 unsigned char *get_unique_name(unsigned char *fileprefix);
44 /** Checks various environment variables to get the name of the temp dir.
45 * Returns a filename by concatenating "<tmpdir>/<name>". */
46 unsigned char *get_tempdir_filename(unsigned char *name);
48 /** Read a line from @a file into the dynamically allocated @a line,
49 * increasing @a line if necessary. Ending whitespace is trimmed.
50 * If a line ends with "\" the next line is read too.
51 * If @a line is NULL the returned line is allocated and if file
52 * reading fails @a line is free()d. */
53 unsigned char *file_read_line(unsigned char *line, size_t *linesize,
54 FILE *file, int *linenumber);
56 /** Safe wrapper for mkstemp().
57 * It enforces permissions by calling umask(0177), call mkstemp(), then
58 * restore previous umask(). */
59 int safe_mkstemp(unsigned char *template);
61 /** Recursively create directories in @a path. The last element in the path is
62 * taken to be a filename, and simply ignored */
63 int mkalldirs(const unsigned char *path);
65 /* comparison function for qsort() */
66 int compare_dir_entries(const void *v1, const void *v2);
69 /** @name The stat_* functions set the various attributes for directory entries.
70 * @{ */
72 static inline void
73 stat_type(struct string *string, struct stat *stp)
75 unsigned char c = '?';
77 if (stp) {
78 if (S_ISDIR(stp->st_mode)) c = 'd';
79 else if (S_ISREG(stp->st_mode)) c = '-';
80 #ifdef S_ISBLK
81 else if (S_ISBLK(stp->st_mode)) c = 'b';
82 #endif
83 #ifdef S_ISCHR
84 else if (S_ISCHR(stp->st_mode)) c = 'c';
85 #endif
86 #ifdef S_ISFIFO
87 else if (S_ISFIFO(stp->st_mode)) c = 'p';
88 #endif
89 #ifdef S_ISLNK
90 else if (S_ISLNK(stp->st_mode)) c = 'l';
91 #endif
92 #ifdef S_ISSOCK
93 else if (S_ISSOCK(stp->st_mode)) c = 's';
94 #endif
95 #ifdef S_ISNWK
96 else if (S_ISNWK(stp->st_mode)) c = 'n';
97 #endif
100 add_char_to_string(string, c);
103 static inline void
104 stat_mode(struct string *string, struct stat *stp)
106 #ifdef FS_UNIX_RIGHTS
107 unsigned char rwx[10] = "---------";
109 if (stp) {
110 mode_t mode = stp->st_mode;
111 unsigned int shift;
113 /* Set permissions attributes for user, group and other */
114 for (shift = 0; shift <= 6; shift += 3) {
115 mode_t m = mode << shift;
117 if (m & S_IRUSR) rwx[shift + 0] = 'r';
118 if (m & S_IWUSR) rwx[shift + 1] = 'w';
119 if (m & S_IXUSR) rwx[shift + 2] = 'x';
122 #ifdef S_ISUID
123 if (mode & S_ISUID)
124 rwx[2] = (mode & S_IXUSR) ? 's' : 'S';
125 #endif
126 #ifdef S_ISGID
127 if (mode & S_ISGID)
128 rwx[5] = (mode & S_IXGRP) ? 's' : 'S';
129 #endif
130 #ifdef S_ISVTX
131 if (mode & S_ISVTX)
132 rwx[8] = (mode & S_IXOTH) ? 't' : 'T';
133 #endif
135 add_to_string(string, rwx);
136 #endif
137 add_char_to_string(string, ' ');
140 static inline void
141 stat_links(struct string *string, struct stat *stp)
143 #ifdef FS_UNIX_HARDLINKS
144 if (!stp) {
145 add_to_string(string, " ");
146 } else {
147 unsigned char lnk[64];
149 ulongcat(lnk, NULL, stp->st_nlink, 3, ' ');
150 add_to_string(string, lnk);
151 add_char_to_string(string, ' ');
153 #endif
156 static inline void
157 stat_user(struct string *string, struct stat *stp)
159 #ifdef FS_UNIX_USERS
160 static unsigned char last_user[64];
161 static int last_uid = -1;
163 if (!stp) {
164 add_to_string(string, " ");
165 return;
168 if (stp->st_uid != last_uid) {
169 struct passwd *pwd = getpwuid(stp->st_uid);
171 if (!pwd || !pwd->pw_name)
172 /* ulongcat() can't pad from right. */
173 snprintf(last_user, 64, "%-8d", (int) stp->st_uid);
174 else
175 snprintf(last_user, 64, "%-8.8s", pwd->pw_name);
177 last_uid = stp->st_uid;
180 add_to_string(string, last_user);
181 add_char_to_string(string, ' ');
182 #endif
185 static inline void
186 stat_group(struct string *string, struct stat *stp)
188 #ifdef FS_UNIX_USERS
189 static unsigned char last_group[64];
190 static int last_gid = -1;
192 if (!stp) {
193 add_to_string(string, " ");
194 return;
197 if (stp->st_gid != last_gid) {
198 struct group *grp = getgrgid(stp->st_gid);
200 if (!grp || !grp->gr_name)
201 /* ulongcat() can't pad from right. */
202 snprintf(last_group, 64, "%-8d", (int) stp->st_gid);
203 else
204 snprintf(last_group, 64, "%-8.8s", grp->gr_name);
206 last_gid = stp->st_gid;
209 add_to_string(string, last_group);
210 add_char_to_string(string, ' ');
211 #endif
214 static inline void
215 stat_size(struct string *string, struct stat *stp)
217 /* Check if st_size will cause overflow. */
218 /* FIXME: See bug 497 for info about support for big files. */
219 if (!stp || stp->st_size != (unsigned long) stp->st_size) {
220 add_to_string(string, " ");
222 } else {
223 unsigned char size[64];
224 int width = 9;
226 /* First try to fit the file size into 8 digits ... */
227 width = ulongcat(size, NULL, stp->st_size, width, ' ');
228 if (0 < width && width < sizeof(size)) {
229 /* ... if that is not enough expand the size buffer.
230 * This will only break the column alignment of the size
231 * attribute if really needed. */
232 ulongcat(size, NULL, stp->st_size, width, ' ');
235 add_to_string(string, size);
236 add_char_to_string(string, ' ');
240 static inline void
241 stat_date(struct string *string, struct stat *stp)
243 #ifdef HAVE_STRFTIME
244 if (stp) {
245 time_t current_time = time(NULL);
246 time_t when = stp->st_mtime;
247 unsigned char *fmt;
249 if (current_time > when + 6L * 30L * 24L * 60L * 60L
250 || current_time < when - 60L * 60L)
251 fmt = "%b %e %Y";
252 else
253 fmt = "%b %e %H:%M";
255 add_date_to_string(string, fmt, &when);
256 add_char_to_string(string, ' ');
257 return;
259 #endif
260 add_to_string(string, " ");
264 #endif