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 i64
de_strtoll(const char *string
, char **endptr
, int base
)
39 return strtoll(string
, endptr
, base
);
42 static FILE* de_fopen(deark
*c
, const char *fn
, const char *mode
,
43 char *errmsg
, size_t errmsg_len
)
51 de_strlcpy(errmsg
, strerror(errcode
), errmsg_len
);
56 // Test if the file seems suitable for reading, and return its size.
57 // returned flags: 0x1 = file is a FIFO (named pipe)
58 static int de_examine_file_by_fd(deark
*c
, int fd
, i64
*len
,
59 char *errmsg
, size_t errmsg_len
, unsigned int *returned_flags
)
64 de_zeromem(&stbuf
, sizeof(struct stat
));
66 if(0 != fstat(fd
, &stbuf
)) {
67 de_strlcpy(errmsg
, strerror(errno
), errmsg_len
);
71 if(S_ISFIFO(stbuf
.st_mode
)) {
72 *returned_flags
|= 0x1;
76 else if(!S_ISREG(stbuf
.st_mode
)) {
77 de_strlcpy(errmsg
, "Not a regular file", errmsg_len
);
81 *len
= (i64
)stbuf
.st_size
;
85 FILE* de_fopen_for_read(deark
*c
, const char *fn
, i64
*len
,
86 char *errmsg
, size_t errmsg_len
, unsigned int *returned_flags
)
91 f
= de_fopen(c
, fn
, "rb", errmsg
, errmsg_len
);
96 ret
= de_examine_file_by_fd(c
, fileno(f
), len
, errmsg
, errmsg_len
,
106 // flags: 0x1 = append instead of overwriting
107 FILE* de_fopen_for_write(deark
*c
, const char *fn
,
108 char *errmsg
, size_t errmsg_len
, int overwrite_mode
,
113 // A simple check to make it harder to accidentally overwrite the input
114 // file. (But it can easily be defeated.)
115 // TODO?: Make this more robust.
116 if(c
->input_filename
&& !de_strcmp(fn
, c
->input_filename
)) {
117 de_err(c
, "Refusing to write to %s: Same as input filename", fn
);
119 de_strlcpy(errmsg
, "", errmsg_len
);
123 if(overwrite_mode
!=DE_OVERWRITEMODE_STANDARD
) {
124 // Check if the file already exists.
128 de_zeromem(&stbuf
, sizeof(struct stat
));
130 s_ret
= lstat(fn
, &stbuf
);
132 s_ret
= stat(fn
, &stbuf
);
135 // s_ret==0 = "success"
136 if(s_ret
==0 && overwrite_mode
==DE_OVERWRITEMODE_NEVER
) {
137 de_strlcpy(errmsg
, "Output file already exists", errmsg_len
);
141 if(s_ret
==0 && overwrite_mode
==DE_OVERWRITEMODE_DEFAULT
) {
142 if(S_ISLNK(stbuf
.st_mode
)) {
143 de_strlcpy(errmsg
, "Output file is a symlink", errmsg_len
);
149 mode
= (flags
&0x1) ? "ab" : "wb";
150 return de_fopen(c
, fn
, mode
, errmsg
, errmsg_len
);
153 int de_fseek(FILE *fp
, i64 offs
, int whence
)
158 ret
= fseeko(fp
, (off_t
)offs
, whence
);
160 ret
= fseek(fp
, (long)offs
, whence
);
165 i64
de_ftell(FILE *fp
)
170 ret
= (i64
)ftello(fp
);
172 ret
= (i64
)ftell(fp
);
177 int de_fclose(FILE *fp
)
182 struct upd_attr_ctx
{
188 // If, based on f->mode_flags, we know that the file should be executable or
189 // non-executable, make it so.
190 static void update_file_perms(struct upd_attr_ctx
*uactx
, dbuf
*f
)
192 mode_t oldmode
, newmode
;
194 if(f
->btype
!=DBUF_TYPE_OFILE
) return;
195 if(!f
->fi_copy
) return;
197 if(!(f
->fi_copy
->mode_flags
&DE_MODEFLAG_NONEXE
) &&!(f
->fi_copy
->mode_flags
&DE_MODEFLAG_EXE
)) return;
199 uactx
->stat_ret
= stat(f
->name
, &uactx
->stbuf
);
200 uactx
->tried_stat
= 1;
201 if(uactx
->stat_ret
!= 0) {
205 oldmode
= uactx
->stbuf
.st_mode
;
208 // Start by turning off the executable bits in the tentative new mode.
209 newmode
&= ~(S_IXUSR
|S_IXGRP
|S_IXOTH
);
211 if(f
->fi_copy
->mode_flags
&DE_MODEFLAG_EXE
) {
212 // Set an Executable bit if its corresponding Read bit is set.
213 if(oldmode
& S_IRUSR
) newmode
|= S_IXUSR
;
214 if(oldmode
& S_IRGRP
) newmode
|= S_IXGRP
;
215 if(oldmode
& S_IROTH
) newmode
|= S_IXOTH
;
218 if(newmode
!= oldmode
) {
219 de_dbg2(f
->c
, "changing file mode from %03o to %03o",
220 (unsigned int)oldmode
, (unsigned int)newmode
);
221 chmod(f
->name
, newmode
);
225 static void update_file_time(struct upd_attr_ctx
*uactx
, dbuf
*f
)
227 const struct de_timestamp
*ts
;
228 struct timeval times
[2];
230 if(f
->btype
!=DBUF_TYPE_OFILE
) return;
231 if(!f
->fi_copy
) return;
232 ts
= &f
->fi_copy
->timestamp
[DE_TIMESTAMPIDX_MODIFY
];
233 if(!ts
->is_valid
) return;
236 if(!uactx
->tried_stat
) {
237 uactx
->stat_ret
= stat(f
->name
, &uactx
->stbuf
);
238 uactx
->tried_stat
= 1;
241 // I know that this code is not Y2038-compliant, if sizeof(time_t)==4.
242 // But it's not likely to be a serious problem, and I'd rather not replace
243 // it with code that's less portable.
245 de_zeromem(×
, sizeof(times
));
246 // times[0] = access time
247 // times[1] = mod time
248 times
[1].tv_sec
= (long)de_timestamp_to_unix_time(ts
);
249 if(ts
->precision
>DE_TSPREC_1SEC
) {
250 times
[1].tv_usec
= (long)(de_timestamp_get_subsec(ts
)/10);
253 // We don't want to set the access time, but unfortunately the utimes()
254 // function forces us to.
255 if(uactx
->tried_stat
&& (uactx
->stat_ret
==0)) {
256 // If we have the file's current access time recorded, use that.
257 // (Though this may lose precision. Which could be fixed at the cost of
259 times
[0].tv_sec
= (long)uactx
->stbuf
.st_atime
;
260 times
[0].tv_usec
= 0;
263 // Otherwise use the mod time.
266 utimes(f
->name
, times
);
269 void de_update_file_attribs(dbuf
*f
, u8 preserve_file_times
)
271 struct upd_attr_ctx uactx
;
273 de_zeromem(&uactx
, sizeof(struct upd_attr_ctx
));
275 update_file_perms(&uactx
, f
);
276 if(preserve_file_times
) {
277 update_file_time(&uactx
, f
);
281 // Note: Need to keep this function in sync with the implementation in deark-win.c.
282 void de_current_time_to_timestamp(struct de_timestamp
*ts
)
287 de_zeromem(&tv
, sizeof(struct timeval
));
288 ret
= gettimeofday(&tv
, NULL
);
290 de_zeromem(ts
, sizeof(struct de_timestamp
));
294 de_unix_time_to_timestamp((i64
)tv
.tv_sec
, ts
, 0x1);
295 de_timestamp_set_subsec(ts
, ((double)tv
.tv_usec
)/1000000.0);
298 void de_exitprocess(int s
)
303 struct de_platform_data
*de_platformdata_create(void)
305 struct de_platform_data
*plctx
;
307 plctx
= de_malloc(NULL
, sizeof(struct de_platform_data
));
311 void de_platformdata_destroy(struct de_platform_data
*plctx
)
314 de_free(NULL
, plctx
);