1 /* ========================================================================
2 * Copyright 1988-2006 University of Washington
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
11 * ========================================================================
15 * Program: Unix compatibility routines
17 * Author: Mark Crispin
18 * Networks and Distributed Computing
19 * Computing & Communications
20 * University of Washington
21 * Administration Building, AG-44
23 * Internet: MRC@CAC.Washington.EDU
25 * Date: 14 September 1996
26 * Last Edited: November 7, 2015.
27 * Eduardo Chappa <chappa@gmx.com>
33 * This file is dedicated to my dog, Unix, also known as Yun-chan and
34 * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix
35 * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
36 * a two-month bout with cirrhosis of the liver.
38 * He was a dear friend, and I miss him terribly.
40 * Lift a leg, Yunie. Luv ya forever!!!!
43 /* Emulator for BSD flock() call
44 * Accepts: file descriptor
46 * Returns: 0 if successful, -1 if failure
49 /* Our friends in Redmond have decided that you can not write to any segment
50 * which has a shared lock. This screws up the shared-write mailbox drivers
51 * (mbx, mtx, and tenex). As a workaround, we'll only lock the first byte of
52 * the file, meaning that you can't write that byte shared.
53 * This behavior seems to be new as of NT 4.0.
56 int flock (int fd
,int op
)
58 HANDLE hdl
= (HANDLE
) _get_osfhandle (fd
);
59 DWORD flags
= (op
& LOCK_NB
) ? LOCKFILE_FAIL_IMMEDIATELY
: 0;
60 OVERLAPPED offset
= {NIL
,NIL
,0,0,NIL
};
62 blocknotify_t bn
= (blocknotify_t
)
63 ((op
& LOCK_NB
) ? NIL
: mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
));
64 if (hdl
< 0) errno
= EBADF
; /* error in file descriptor */
65 else switch (op
& ~LOCK_NB
) { /* translate to LockFileEx() op */
66 case LOCK_EX
: /* exclusive */
67 flags
|= LOCKFILE_EXCLUSIVE_LOCK
;
68 case LOCK_SH
: /* shared */
69 if (!check_nt ()) return 0; /* always succeeds if not NT */
70 if (bn
) (*bn
) (BLOCK_FILELOCK
,NIL
);
71 /* bug for bug compatible with Unix */
72 UnlockFileEx (hdl
,NIL
,1,0,&offset
);
73 /* lock the file as requested */
74 if (LockFileEx (hdl
,flags
,NIL
,1,0,&offset
)) ret
= 0;
75 if (bn
) (*bn
) (BLOCK_NONE
,NIL
);
77 if (ret
) errno
= (op
& LOCK_NB
) ? EAGAIN
: EBADF
;
79 case LOCK_UN
: /* unlock */
80 if (check_nt ()) UnlockFileEx (hdl
,NIL
,1,0,&offset
);
81 ret
= 0; /* always succeeds */
82 default: /* default */
83 errno
= EINVAL
; /* bad call */
91 static char *loghdr
; /* log file header string */
92 static HANDLE loghdl
= NIL
; /* handle of event source */
94 /* Emulator for BSD syslog() routine
100 void syslog (int priority
,const char *message
,...)
104 char tmp
[MAILTMPLEN
]; /* callers must be careful not to pop this */
105 unsigned short etype
;
106 if (!check_nt ()) return; /* no-op on non-NT system */
107 /* default event source */
108 if (!loghdl
) openlog ("c-client",LOG_PID
,LOG_MAIL
);
109 switch (priority
) { /* translate UNIX type into NT type */
111 etype
= EVENTLOG_ERROR_TYPE
;
114 etype
= EVENTLOG_INFORMATION_TYPE
;
117 etype
= EVENTLOG_WARNING_TYPE
;
119 va_start (args
,message
); /* initialize vararg mechanism */
120 vsprintf (tmp
,message
,args
); /* build message */
121 strs
[0] = loghdr
; /* write header */
122 strs
[1] = tmp
; /* then the message */
123 /* report the event */
124 ReportEvent (loghdl
,etype
,(unsigned short) priority
,2000,NIL
,2,0,strs
,NIL
);
129 /* Emulator for BSD openlog() routine
135 void openlog (const char *ident
,int logopt
,int facility
)
137 char tmp
[MAILTMPLEN
];
138 if (!check_nt ()) return; /* no-op on non-NT system */
139 if (loghdl
) fatal ("Duplicate openlog()!");
140 loghdl
= RegisterEventSource (NIL
,ident
);
141 sprintf (tmp
,(logopt
& LOG_PID
) ? "%s[%d]" : "%s",ident
,getpid ());
142 loghdr
= cpystr (tmp
); /* save header for later */
145 /* Copy Unix string with CRLF newlines
146 * Accepts: destination string
147 * pointer to size of destination string buffer
149 * length of source string
150 * Returns: length of copied string
153 unsigned long unix_crlfcpy (char **dst
,unsigned long *dstl
,char *src
,
158 /* count number of LF's in source string(s) */
159 for (i
= srcl
,j
= 0; j
< srcl
; j
++) if (*d
++ == '\012') i
++;
160 /* flush destination buffer if too small */
161 if (*dst
&& (i
> *dstl
)) fs_give ((void **) dst
);
162 if (!*dst
) { /* make a new buffer if needed */
163 *dst
= (char *) fs_get ((*dstl
= i
) + 1);
164 if (dstl
) *dstl
= i
; /* return new buffer length to main program */
166 d
= *dst
; /* destination string */
167 /* copy strings, inserting CR's before LF's */
168 while (srcl
--) switch (*src
) {
169 case '\015': /* unlikely carriage return */
170 *d
++ = *src
++; /* copy it and any succeeding linefeed */
171 if (srcl
&& *src
== '\012') {
176 case '\012': /* line feed? */
177 *d
++ ='\015'; /* yes, prepend a CR, drop into default case */
178 default: /* ordinary character */
179 *d
++ = *src
++; /* just copy character */
182 *d
= '\0'; /* tie off destination */
183 return d
- *dst
; /* return length */
186 /* Length of Unix string after unix_crlfcpy applied
187 * Accepts: source string
188 * Returns: length of string
191 unsigned long unix_crlflen (STRING
*s
)
193 unsigned long pos
= GETPOS (s
);
194 unsigned long i
= SIZE (s
);
196 while (j
--) switch (SNX (s
)) {/* search for newlines */
197 case '\015': /* unlikely carriage return */
198 if (j
&& (CHR (s
) == '\012')) {
199 SNX (s
); /* eat the line feed */
203 case '\012': /* line feed? */
205 default: /* ordinary character */
208 SETPOS (s
,pos
); /* restore old position */
212 /* Undoubtedly, I'm going to regret these two routines in the future. I
213 * regret them now. Their purpose is to work around two problems in the
214 * VC++ 6.0 C library:
215 * (1) tmpfile() creates the file in the current directory instead of a
216 * temporary directory
217 * (2) tmpfile() and fclose() think that on NT systems, it works to unlink
218 * the file while it's still open, so there's no need for the _tmpfname
219 * hook at fclose(). Unfortunately, that doesn't work in Win2K.
220 * I would be delighted to have a better alternative.
222 /* So Visual Studio 2015 came along and it made a change to the FILE structure
223 * so it is not possible to use _tmpfname to store the name of the temporary
224 * file name, so we will introduce an internal management system to keep track
225 * of temporary files. E.Ch.
228 typedef struct win_file
{
233 typedef struct wintmpfile
{
234 WIN_FILE_S
*wf
; /* where memory is saved */
235 int size
; /* size of array of allocated memory */
236 int total
; /* total number of allocated members */
239 #define TMPFILE_NUM 5 /* increase every 5 files, if we need to */
243 void add_tmpfile(TMP_WINFILE
*wtmp
, FILE *f
, char *name
)
248 if(wtmp
->total
% TMPFILE_NUM
== 0){
249 wtmp
->size
+= TMPFILE_NUM
;
250 fs_resize((void **)&wtmp
->wf
, wtmp
->size
*sizeof(WIN_FILE_S
));
253 wtmp
->wf
[wtmp
->total
].f
= f
;
254 wtmp
->wf
[wtmp
->total
++].name
= name
;
257 int get_pos_tmpfile(TMP_WINFILE
*wtmp
, FILE *f
)
261 if(wtmp
== NULL
|| wtmp
->total
== 0)
264 for(i
= 0; i
< wtmp
->total
&& wtmp
->wf
[i
].f
!= f
; i
++);
266 return i
== wtmp
->total
? -1 : i
;
269 /* remove the element in position pos from wtmp, all memory is freed before
270 * calling this function */
271 void remove_pos_tmpfile(TMP_WINFILE
*wtmp
, int pos
)
275 if(wtmp
== NULL
|| pos
< 0 || pos
>= wtmp
->total
)
279 for(i
= pos
; i
< wtmp
->total
; i
++){
280 wtmp
->wf
[i
].f
= wtmp
->wf
[i
+1].f
;
281 wtmp
->wf
[i
].name
= wtmp
->wf
[i
+1].name
;
283 wtmp
->wf
[wtmp
->total
].f
= NIL
;
284 wtmp
->wf
[wtmp
->total
].name
= NIL
;
286 if(wtmp
->total
% TMPFILE_NUM
== 0){
287 wtmp
->size
-= TMPFILE_NUM
;
288 fs_resize((void **)&wtmp
->wf
, wtmp
->size
*sizeof(WIN_FILE_S
));
291 inited
= 0; /* restart */
294 #undef fclose /* use the real fclose() in close_file() */
296 /* Substitute for Microsoft's tmpfile() that uses the real temporary directory
297 * Returns: FILE structure if success, NIL if failure
300 FILE *create_tempfile (void)
303 char *s
= _tempnam (getenv ("TEMP"),"msg");
305 if(inited
== 0){ /* initialize, just in case */
306 memset((void *)&win_tmp
, 0, sizeof(TMP_WINFILE
));
309 if (s
) { /* if got temporary name... */
310 /* open file, and stash name on record of temp files */
311 if (ret
= fopen (s
,"w+b")) add_tmpfile(&win_tmp
, ret
, s
);
312 else fs_give ((void **) &s
);/* flush temporary string */
318 /* Substitute for Microsoft's fclose() that always flushes _tmpfname
319 * Returns: FILE structure if success, NIL if failure
322 int close_file (FILE *stream
)
325 int pos
= get_pos_tmpfile(&win_tmp
, stream
);
326 ret
= fclose (stream
); /* close the file */
327 if (pos
>= 0) { /* was this a temporary file? */
328 unlink (win_tmp
.wf
[pos
].name
); /* if so, delete it */
329 fs_give ((void **) &win_tmp
.wf
[pos
].name
); /* and flush the name */
330 remove_pos_tmpfile(&win_tmp
, pos
);
335 /* Get password from console
340 #define PWDLEN 128 /* used by Linux */
342 char *getpass (const char *prompt
)
344 static char pwd
[PWDLEN
];
346 fputs (prompt
,stderr
); /* output prompt */
347 for (i
= done
= 0; !done
; ) switch (ch
= _getch()) {
348 case 0x03: /* CTRL/C stops program */
350 case '\b': /* BACKSPACE erase previous character */
351 if (i
) pwd
[--i
] = '\0';
353 case '\n': case '\r': /* CR or LF terminates string */
356 default: /* any other character is a pwd char */
357 if (i
< (PWDLEN
- 1)) pwd
[i
++] = ch
;
360 pwd
[i
] = '\0'; /* tie off string with null */
361 putchar ('\n'); /* echo newline */