1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Functions specific to Unix and other non-Windows builds
7 #define DE_NOT_IN_MODULE
8 #include "deark-config.h"
13 #include <sys/types.h>
19 // This file is overloaded, in that it contains functions intended to only
20 // be used internally, as well as functions intended only for the
21 // command-line utility. That's why we need both deark-user.h and
23 #include "deark-private.h"
24 #include "deark-user.h"
26 // Unix-specific contextual data, not currently used.
27 struct de_platform_data
{
31 void de_vsnprintf(char *buf
, size_t buflen
, const char *fmt
, va_list ap
)
33 vsnprintf(buf
,buflen
,fmt
,ap
);
37 char *de_strdup(deark
*c
, const char *s
)
43 de_err(c
, "Memory allocation failed");
50 i64
de_strtoll(const char *string
, char **endptr
, int base
)
52 return strtoll(string
, endptr
, base
);
55 static FILE* de_fopen(deark
*c
, const char *fn
, const char *mode
,
56 char *errmsg
, size_t errmsg_len
)
64 de_strlcpy(errmsg
, strerror(errcode
), errmsg_len
);
69 // Test if the file seems suitable for reading, and return its size.
70 // returned flags: 0x1 = file is a FIFO (named pipe)
71 static int de_examine_file_by_fd(deark
*c
, int fd
, i64
*len
,
72 char *errmsg
, size_t errmsg_len
, unsigned int *returned_flags
)
77 de_zeromem(&stbuf
, sizeof(struct stat
));
79 if(0 != fstat(fd
, &stbuf
)) {
80 de_strlcpy(errmsg
, strerror(errno
), errmsg_len
);
84 if(S_ISFIFO(stbuf
.st_mode
)) {
85 *returned_flags
|= 0x1;
89 else if(!S_ISREG(stbuf
.st_mode
)) {
90 de_strlcpy(errmsg
, "Not a regular file", errmsg_len
);
94 *len
= (i64
)stbuf
.st_size
;
98 FILE* de_fopen_for_read(deark
*c
, const char *fn
, i64
*len
,
99 char *errmsg
, size_t errmsg_len
, unsigned int *returned_flags
)
104 f
= de_fopen(c
, fn
, "rb", errmsg
, errmsg_len
);
109 ret
= de_examine_file_by_fd(c
, fileno(f
), len
, errmsg
, errmsg_len
,
119 // flags: 0x1 = append instead of overwriting
120 FILE* de_fopen_for_write(deark
*c
, const char *fn
,
121 char *errmsg
, size_t errmsg_len
, int overwrite_mode
,
126 // A simple check to make it harder to accidentally overwrite the input
127 // file. (But it can easily be defeated.)
128 // TODO?: Make this more robust.
129 if(c
->input_filename
&& !de_strcmp(fn
, c
->input_filename
)) {
130 de_err(c
, "Refusing to write to %s: Same as input filename", fn
);
132 de_strlcpy(errmsg
, "", errmsg_len
);
136 if(overwrite_mode
!=DE_OVERWRITEMODE_STANDARD
) {
137 // Check if the file already exists.
141 de_zeromem(&stbuf
, sizeof(struct stat
));
143 s_ret
= lstat(fn
, &stbuf
);
145 s_ret
= stat(fn
, &stbuf
);
148 // s_ret==0 = "success"
149 if(s_ret
==0 && overwrite_mode
==DE_OVERWRITEMODE_NEVER
) {
150 de_strlcpy(errmsg
, "Output file already exists", errmsg_len
);
154 if(s_ret
==0 && overwrite_mode
==DE_OVERWRITEMODE_DEFAULT
) {
155 if ((stbuf
.st_mode
& S_IFMT
) == S_IFLNK
) {
156 de_strlcpy(errmsg
, "Output file is a symlink", errmsg_len
);
162 mode
= (flags
&0x1) ? "ab" : "wb";
163 return de_fopen(c
, fn
, mode
, errmsg
, errmsg_len
);
166 int de_fseek(FILE *fp
, i64 offs
, int whence
)
171 ret
= fseeko(fp
, (off_t
)offs
, whence
);
173 ret
= fseek(fp
, (long)offs
, whence
);
178 i64
de_ftell(FILE *fp
)
183 ret
= (i64
)ftello(fp
);
185 ret
= (i64
)ftell(fp
);
190 int de_fclose(FILE *fp
)
195 struct upd_attr_ctx
{
201 // If, based on f->mode_flags, we know that the file should be executable or
202 // non-executable, make it so.
203 static void update_file_perms(struct upd_attr_ctx
*uactx
, dbuf
*f
)
205 mode_t oldmode
, newmode
;
207 if(f
->btype
!=DBUF_TYPE_OFILE
) return;
208 if(!f
->fi_copy
) return;
210 if(!(f
->fi_copy
->mode_flags
&DE_MODEFLAG_NONEXE
) &&!(f
->fi_copy
->mode_flags
&DE_MODEFLAG_EXE
)) return;
212 uactx
->stat_ret
= stat(f
->name
, &uactx
->stbuf
);
213 uactx
->tried_stat
= 1;
214 if(uactx
->stat_ret
!= 0) {
218 oldmode
= uactx
->stbuf
.st_mode
;
221 // Start by turning off the executable bits in the tentative new mode.
222 newmode
&= ~(S_IXUSR
|S_IXGRP
|S_IXOTH
);
224 if(f
->fi_copy
->mode_flags
&DE_MODEFLAG_EXE
) {
225 // Set an Executable bit if its corresponding Read bit is set.
226 if(oldmode
& S_IRUSR
) newmode
|= S_IXUSR
;
227 if(oldmode
& S_IRGRP
) newmode
|= S_IXGRP
;
228 if(oldmode
& S_IROTH
) newmode
|= S_IXOTH
;
231 if(newmode
!= oldmode
) {
232 de_dbg2(f
->c
, "changing file mode from %03o to %03o",
233 (unsigned int)oldmode
, (unsigned int)newmode
);
234 chmod(f
->name
, newmode
);
238 static void update_file_time(struct upd_attr_ctx
*uactx
, dbuf
*f
)
240 const struct de_timestamp
*ts
;
241 struct timeval times
[2];
243 if(f
->btype
!=DBUF_TYPE_OFILE
) return;
244 if(!f
->fi_copy
) return;
245 ts
= &f
->fi_copy
->timestamp
[DE_TIMESTAMPIDX_MODIFY
];
246 if(!ts
->is_valid
) return;
249 if(!uactx
->tried_stat
) {
250 uactx
->stat_ret
= stat(f
->name
, &uactx
->stbuf
);
251 uactx
->tried_stat
= 1;
254 // I know that this code is not Y2038-compliant, if sizeof(time_t)==4.
255 // But it's not likely to be a serious problem, and I'd rather not replace
256 // it with code that's less portable.
258 de_zeromem(×
, sizeof(times
));
259 // times[0] = access time
260 // times[1] = mod time
261 times
[1].tv_sec
= (long)de_timestamp_to_unix_time(ts
);
262 if(ts
->precision
>DE_TSPREC_1SEC
) {
263 times
[1].tv_usec
= (long)(de_timestamp_get_subsec(ts
)/10);
266 // We don't want to set the access time, but unfortunately the utimes()
267 // function forces us to.
268 if(uactx
->tried_stat
&& (uactx
->stat_ret
==0)) {
269 // If we have the file's current access time recorded, use that.
270 // (Though this may lose precision. Which could be fixed at the cost of
272 times
[0].tv_sec
= (long)uactx
->stbuf
.st_atime
;
273 times
[0].tv_usec
= 0;
276 // Otherwise use the mod time.
279 utimes(f
->name
, times
);
282 void de_update_file_attribs(dbuf
*f
, u8 preserve_file_times
)
284 struct upd_attr_ctx uactx
;
286 de_zeromem(&uactx
, sizeof(struct upd_attr_ctx
));
288 update_file_perms(&uactx
, f
);
289 if(preserve_file_times
) {
290 update_file_time(&uactx
, f
);
294 // Note: Need to keep this function in sync with the implementation in deark-win.c.
295 void de_current_time_to_timestamp(struct de_timestamp
*ts
)
300 de_zeromem(&tv
, sizeof(struct timeval
));
301 ret
= gettimeofday(&tv
, NULL
);
303 de_zeromem(ts
, sizeof(struct de_timestamp
));
307 de_unix_time_to_timestamp((i64
)tv
.tv_sec
, ts
, 0x1);
308 de_timestamp_set_subsec(ts
, ((double)tv
.tv_usec
)/1000000.0);
311 void de_exitprocess(int s
)
316 struct de_platform_data
*de_platformdata_create(void)
318 struct de_platform_data
*plctx
;
320 plctx
= de_malloc(NULL
, sizeof(struct de_platform_data
));
324 void de_platformdata_destroy(struct de_platform_data
*plctx
)
327 de_free(NULL
, plctx
);