file: Better support for trailing slashes in pathnames
[jimtcl.git] / jimiocompat.c
blobc8c3f863166621f84ada4b39aeba205d6fdaa2d2
1 #include <string.h>
2 #include "jimiocompat.h"
4 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
6 Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
9 #if defined(__MINGW32__)
10 #include <sys/stat.h>
12 int Jim_Errno(void)
14 switch (GetLastError()) {
15 case ERROR_FILE_NOT_FOUND: return ENOENT;
16 case ERROR_PATH_NOT_FOUND: return ENOENT;
17 case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
18 case ERROR_ACCESS_DENIED: return EACCES;
19 case ERROR_INVALID_HANDLE: return EBADF;
20 case ERROR_BAD_ENVIRONMENT: return E2BIG;
21 case ERROR_BAD_FORMAT: return ENOEXEC;
22 case ERROR_INVALID_ACCESS: return EACCES;
23 case ERROR_INVALID_DRIVE: return ENOENT;
24 case ERROR_CURRENT_DIRECTORY: return EACCES;
25 case ERROR_NOT_SAME_DEVICE: return EXDEV;
26 case ERROR_NO_MORE_FILES: return ENOENT;
27 case ERROR_WRITE_PROTECT: return EROFS;
28 case ERROR_BAD_UNIT: return ENXIO;
29 case ERROR_NOT_READY: return EBUSY;
30 case ERROR_BAD_COMMAND: return EIO;
31 case ERROR_CRC: return EIO;
32 case ERROR_BAD_LENGTH: return EIO;
33 case ERROR_SEEK: return EIO;
34 case ERROR_WRITE_FAULT: return EIO;
35 case ERROR_READ_FAULT: return EIO;
36 case ERROR_GEN_FAILURE: return EIO;
37 case ERROR_SHARING_VIOLATION: return EACCES;
38 case ERROR_LOCK_VIOLATION: return EACCES;
39 case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
40 case ERROR_HANDLE_DISK_FULL: return ENOSPC;
41 case ERROR_NOT_SUPPORTED: return ENODEV;
42 case ERROR_REM_NOT_LIST: return EBUSY;
43 case ERROR_DUP_NAME: return EEXIST;
44 case ERROR_BAD_NETPATH: return ENOENT;
45 case ERROR_NETWORK_BUSY: return EBUSY;
46 case ERROR_DEV_NOT_EXIST: return ENODEV;
47 case ERROR_TOO_MANY_CMDS: return EAGAIN;
48 case ERROR_ADAP_HDW_ERR: return EIO;
49 case ERROR_BAD_NET_RESP: return EIO;
50 case ERROR_UNEXP_NET_ERR: return EIO;
51 case ERROR_NETNAME_DELETED: return ENOENT;
52 case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
53 case ERROR_BAD_DEV_TYPE: return ENODEV;
54 case ERROR_BAD_NET_NAME: return ENOENT;
55 case ERROR_TOO_MANY_NAMES: return ENFILE;
56 case ERROR_TOO_MANY_SESS: return EIO;
57 case ERROR_SHARING_PAUSED: return EAGAIN;
58 case ERROR_REDIR_PAUSED: return EAGAIN;
59 case ERROR_FILE_EXISTS: return EEXIST;
60 case ERROR_CANNOT_MAKE: return ENOSPC;
61 case ERROR_OUT_OF_STRUCTURES: return ENFILE;
62 case ERROR_ALREADY_ASSIGNED: return EEXIST;
63 case ERROR_INVALID_PASSWORD: return EPERM;
64 case ERROR_NET_WRITE_FAULT: return EIO;
65 case ERROR_NO_PROC_SLOTS: return EAGAIN;
66 case ERROR_DISK_CHANGE: return EXDEV;
67 case ERROR_BROKEN_PIPE: return EPIPE;
68 case ERROR_OPEN_FAILED: return ENOENT;
69 case ERROR_DISK_FULL: return ENOSPC;
70 case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
71 case ERROR_INVALID_TARGET_HANDLE: return EBADF;
72 case ERROR_INVALID_NAME: return ENOENT;
73 case ERROR_PROC_NOT_FOUND: return ESRCH;
74 case ERROR_WAIT_NO_CHILDREN: return ECHILD;
75 case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
76 case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
77 case ERROR_SEEK_ON_DEVICE: return ESPIPE;
78 case ERROR_BUSY_DRIVE: return EAGAIN;
79 case ERROR_DIR_NOT_EMPTY: return EEXIST;
80 case ERROR_NOT_LOCKED: return EACCES;
81 case ERROR_BAD_PATHNAME: return ENOENT;
82 case ERROR_LOCK_FAILED: return EACCES;
83 case ERROR_ALREADY_EXISTS: return EEXIST;
84 case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
85 case ERROR_BAD_PIPE: return EPIPE;
86 case ERROR_PIPE_BUSY: return EAGAIN;
87 case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
88 case ERROR_DIRECTORY: return ENOTDIR;
90 return EINVAL;
93 pidtype waitpid(pidtype pid, int *status, int nohang)
95 DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
96 if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
97 /* WAIT_TIMEOUT can only happend with WNOHANG */
98 return JIM_BAD_PID;
100 GetExitCodeProcess(pid, &ret);
101 *status = ret;
102 CloseHandle(pid);
103 return pid;
106 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
108 char name[MAX_PATH];
109 HANDLE handle;
111 if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
112 return -1;
115 handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
116 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
117 NULL);
119 if (handle == INVALID_HANDLE_VALUE) {
120 goto error;
123 Jim_SetResultString(interp, name, -1);
124 return _open_osfhandle((int)handle, _O_RDWR | _O_TEXT);
126 error:
127 Jim_SetResultErrno(interp, name);
128 DeleteFile(name);
129 return -1;
132 int Jim_OpenForWrite(const char *filename, int append)
134 if (strcmp(filename, "/dev/null") == 0) {
135 filename = "nul:";
137 int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
138 if (fd >= 0 && append) {
139 /* Note that _O_APPEND doesn't actually work. need to do it manually */
140 _lseek(fd, 0L, SEEK_END);
142 return fd;
145 int Jim_OpenForRead(const char *filename)
147 if (strcmp(filename, "/dev/null") == 0) {
148 filename = "nul:";
150 return _open(filename, _O_RDONLY | _O_TEXT, 0);
153 #elif defined(HAVE_UNISTD_H)
155 /* Unix-specific implementation */
157 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
159 int fd;
160 mode_t mask;
161 Jim_Obj *filenameObj;
163 if (filename_template == NULL) {
164 const char *tmpdir = getenv("TMPDIR");
165 if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
166 tmpdir = "/tmp/";
168 filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
169 if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
170 Jim_AppendString(interp, filenameObj, "/", 1);
172 Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
174 else {
175 filenameObj = Jim_NewStringObj(interp, filename_template, -1);
178 /* Update the template name directly with the filename */
179 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
180 #ifdef HAVE_MKSTEMP
181 fd = mkstemp(filenameObj->bytes);
182 #else
183 if (mktemp(filenameObj->bytes) == NULL) {
184 fd = -1;
186 else {
187 fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
189 #endif
190 umask(mask);
191 if (fd < 0) {
192 Jim_SetResultErrno(interp, Jim_String(filenameObj));
193 Jim_FreeNewObj(interp, filenameObj);
194 return -1;
196 if (unlink_file) {
197 remove(Jim_String(filenameObj));
200 Jim_SetResult(interp, filenameObj);
201 return fd;
204 int Jim_OpenForWrite(const char *filename, int append)
206 return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
209 int Jim_OpenForRead(const char *filename)
211 return open(filename, O_RDONLY, 0);
214 #endif