215 lines
6.8 KiB
C
215 lines
6.8 KiB
C
|
#include <string.h>
|
||
|
#include "jimiocompat.h"
|
||
|
|
||
|
void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
|
||
|
{
|
||
|
Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
|
||
|
}
|
||
|
|
||
|
#if defined(__MINGW32__)
|
||
|
#include <sys/stat.h>
|
||
|
|
||
|
int Jim_Errno(void)
|
||
|
{
|
||
|
switch (GetLastError()) {
|
||
|
case ERROR_FILE_NOT_FOUND: return ENOENT;
|
||
|
case ERROR_PATH_NOT_FOUND: return ENOENT;
|
||
|
case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
|
||
|
case ERROR_ACCESS_DENIED: return EACCES;
|
||
|
case ERROR_INVALID_HANDLE: return EBADF;
|
||
|
case ERROR_BAD_ENVIRONMENT: return E2BIG;
|
||
|
case ERROR_BAD_FORMAT: return ENOEXEC;
|
||
|
case ERROR_INVALID_ACCESS: return EACCES;
|
||
|
case ERROR_INVALID_DRIVE: return ENOENT;
|
||
|
case ERROR_CURRENT_DIRECTORY: return EACCES;
|
||
|
case ERROR_NOT_SAME_DEVICE: return EXDEV;
|
||
|
case ERROR_NO_MORE_FILES: return ENOENT;
|
||
|
case ERROR_WRITE_PROTECT: return EROFS;
|
||
|
case ERROR_BAD_UNIT: return ENXIO;
|
||
|
case ERROR_NOT_READY: return EBUSY;
|
||
|
case ERROR_BAD_COMMAND: return EIO;
|
||
|
case ERROR_CRC: return EIO;
|
||
|
case ERROR_BAD_LENGTH: return EIO;
|
||
|
case ERROR_SEEK: return EIO;
|
||
|
case ERROR_WRITE_FAULT: return EIO;
|
||
|
case ERROR_READ_FAULT: return EIO;
|
||
|
case ERROR_GEN_FAILURE: return EIO;
|
||
|
case ERROR_SHARING_VIOLATION: return EACCES;
|
||
|
case ERROR_LOCK_VIOLATION: return EACCES;
|
||
|
case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
|
||
|
case ERROR_HANDLE_DISK_FULL: return ENOSPC;
|
||
|
case ERROR_NOT_SUPPORTED: return ENODEV;
|
||
|
case ERROR_REM_NOT_LIST: return EBUSY;
|
||
|
case ERROR_DUP_NAME: return EEXIST;
|
||
|
case ERROR_BAD_NETPATH: return ENOENT;
|
||
|
case ERROR_NETWORK_BUSY: return EBUSY;
|
||
|
case ERROR_DEV_NOT_EXIST: return ENODEV;
|
||
|
case ERROR_TOO_MANY_CMDS: return EAGAIN;
|
||
|
case ERROR_ADAP_HDW_ERR: return EIO;
|
||
|
case ERROR_BAD_NET_RESP: return EIO;
|
||
|
case ERROR_UNEXP_NET_ERR: return EIO;
|
||
|
case ERROR_NETNAME_DELETED: return ENOENT;
|
||
|
case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
|
||
|
case ERROR_BAD_DEV_TYPE: return ENODEV;
|
||
|
case ERROR_BAD_NET_NAME: return ENOENT;
|
||
|
case ERROR_TOO_MANY_NAMES: return ENFILE;
|
||
|
case ERROR_TOO_MANY_SESS: return EIO;
|
||
|
case ERROR_SHARING_PAUSED: return EAGAIN;
|
||
|
case ERROR_REDIR_PAUSED: return EAGAIN;
|
||
|
case ERROR_FILE_EXISTS: return EEXIST;
|
||
|
case ERROR_CANNOT_MAKE: return ENOSPC;
|
||
|
case ERROR_OUT_OF_STRUCTURES: return ENFILE;
|
||
|
case ERROR_ALREADY_ASSIGNED: return EEXIST;
|
||
|
case ERROR_INVALID_PASSWORD: return EPERM;
|
||
|
case ERROR_NET_WRITE_FAULT: return EIO;
|
||
|
case ERROR_NO_PROC_SLOTS: return EAGAIN;
|
||
|
case ERROR_DISK_CHANGE: return EXDEV;
|
||
|
case ERROR_BROKEN_PIPE: return EPIPE;
|
||
|
case ERROR_OPEN_FAILED: return ENOENT;
|
||
|
case ERROR_DISK_FULL: return ENOSPC;
|
||
|
case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
|
||
|
case ERROR_INVALID_TARGET_HANDLE: return EBADF;
|
||
|
case ERROR_INVALID_NAME: return ENOENT;
|
||
|
case ERROR_PROC_NOT_FOUND: return ESRCH;
|
||
|
case ERROR_WAIT_NO_CHILDREN: return ECHILD;
|
||
|
case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
|
||
|
case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
|
||
|
case ERROR_SEEK_ON_DEVICE: return ESPIPE;
|
||
|
case ERROR_BUSY_DRIVE: return EAGAIN;
|
||
|
case ERROR_DIR_NOT_EMPTY: return EEXIST;
|
||
|
case ERROR_NOT_LOCKED: return EACCES;
|
||
|
case ERROR_BAD_PATHNAME: return ENOENT;
|
||
|
case ERROR_LOCK_FAILED: return EACCES;
|
||
|
case ERROR_ALREADY_EXISTS: return EEXIST;
|
||
|
case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
|
||
|
case ERROR_BAD_PIPE: return EPIPE;
|
||
|
case ERROR_PIPE_BUSY: return EAGAIN;
|
||
|
case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
|
||
|
case ERROR_DIRECTORY: return ENOTDIR;
|
||
|
}
|
||
|
return EINVAL;
|
||
|
}
|
||
|
|
||
|
pidtype waitpid(pidtype pid, int *status, int nohang)
|
||
|
{
|
||
|
DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
|
||
|
if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
|
||
|
/* WAIT_TIMEOUT can only happend with WNOHANG */
|
||
|
return JIM_BAD_PID;
|
||
|
}
|
||
|
GetExitCodeProcess(pid, &ret);
|
||
|
*status = ret;
|
||
|
CloseHandle(pid);
|
||
|
return pid;
|
||
|
}
|
||
|
|
||
|
int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
|
||
|
{
|
||
|
char name[MAX_PATH];
|
||
|
HANDLE handle;
|
||
|
|
||
|
if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||
|
CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
|
||
|
NULL);
|
||
|
|
||
|
if (handle == INVALID_HANDLE_VALUE) {
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
Jim_SetResultString(interp, name, -1);
|
||
|
return _open_osfhandle((int)handle, _O_RDWR | _O_TEXT);
|
||
|
|
||
|
error:
|
||
|
Jim_SetResultErrno(interp, name);
|
||
|
DeleteFile(name);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int Jim_OpenForWrite(const char *filename, int append)
|
||
|
{
|
||
|
if (strcmp(filename, "/dev/null") == 0) {
|
||
|
filename = "nul:";
|
||
|
}
|
||
|
int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
|
||
|
if (fd >= 0 && append) {
|
||
|
/* Note that _O_APPEND doesn't actually work. need to do it manually */
|
||
|
_lseek(fd, 0L, SEEK_END);
|
||
|
}
|
||
|
return fd;
|
||
|
}
|
||
|
|
||
|
int Jim_OpenForRead(const char *filename)
|
||
|
{
|
||
|
if (strcmp(filename, "/dev/null") == 0) {
|
||
|
filename = "nul:";
|
||
|
}
|
||
|
return _open(filename, _O_RDONLY | _O_TEXT, 0);
|
||
|
}
|
||
|
|
||
|
#elif defined(HAVE_UNISTD_H)
|
||
|
|
||
|
/* Unix-specific implementation */
|
||
|
|
||
|
int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
|
||
|
{
|
||
|
int fd;
|
||
|
mode_t mask;
|
||
|
Jim_Obj *filenameObj;
|
||
|
|
||
|
if (filename_template == NULL) {
|
||
|
const char *tmpdir = getenv("TMPDIR");
|
||
|
if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
|
||
|
tmpdir = "/tmp/";
|
||
|
}
|
||
|
filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
|
||
|
if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
|
||
|
Jim_AppendString(interp, filenameObj, "/", 1);
|
||
|
}
|
||
|
Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
|
||
|
}
|
||
|
else {
|
||
|
filenameObj = Jim_NewStringObj(interp, filename_template, -1);
|
||
|
}
|
||
|
|
||
|
/* Update the template name directly with the filename */
|
||
|
mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
|
||
|
#ifdef HAVE_MKSTEMP
|
||
|
fd = mkstemp(filenameObj->bytes);
|
||
|
#else
|
||
|
if (mktemp(filenameObj->bytes) == NULL) {
|
||
|
fd = -1;
|
||
|
}
|
||
|
else {
|
||
|
fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
|
||
|
}
|
||
|
#endif
|
||
|
umask(mask);
|
||
|
if (fd < 0) {
|
||
|
Jim_SetResultErrno(interp, Jim_String(filenameObj));
|
||
|
Jim_FreeNewObj(interp, filenameObj);
|
||
|
return -1;
|
||
|
}
|
||
|
if (unlink_file) {
|
||
|
remove(Jim_String(filenameObj));
|
||
|
}
|
||
|
|
||
|
Jim_SetResult(interp, filenameObj);
|
||
|
return fd;
|
||
|
}
|
||
|
|
||
|
int Jim_OpenForWrite(const char *filename, int append)
|
||
|
{
|
||
|
return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
|
||
|
}
|
||
|
|
||
|
int Jim_OpenForRead(const char *filename)
|
||
|
{
|
||
|
return open(filename, O_RDONLY, 0);
|
||
|
}
|
||
|
|
||
|
#endif
|