[asperl] integrate latest win32 branch
[p5sagit/p5-mst-13.2.git] / win32 / iplio.c
1 /*
2
3         iplio.c
4         Interface for perl Low IO functions
5
6 */
7
8 #include <iplio.h>
9 #include <sys/utime.h>
10
11
12 class CPerlLIO : public IPerlLIO
13 {
14 public:
15         CPerlLIO() { w32_platform = (-1); pPerl = NULL; pSock = NULL; pStdIO = NULL; };
16
17         virtual int Access(const char *path, int mode, int &err);
18         virtual int Chmod(const char *filename, int pmode, int &err);
19         virtual int Chsize(int handle, long size, int &err);
20         virtual int Close(int handle, int &err);
21         virtual int Dup(int handle, int &err);
22         virtual int Dup2(int handle1, int handle2, int &err);
23         virtual int Flock(int fd, int oper, int &err);
24         virtual int FStat(int handle, struct stat *buffer, int &err);
25         virtual int IOCtl(int i, unsigned int u, char *data, int &err);
26         virtual int Isatty(int handle, int &err);
27         virtual long Lseek(int handle, long offset, int origin, int &err);
28         virtual int Lstat(const char *path, struct stat *buffer, int &err);
29         virtual char *Mktemp(char *Template, int &err);
30         virtual int Open(const char *filename, int oflag, int &err);    
31         virtual int Open(const char *filename, int oflag, int pmode, int &err); 
32         virtual int Read(int handle, void *buffer, unsigned int count, int &err);
33         virtual int Rename(const char *oldname, const char *newname, int &err);
34         virtual int Setmode(int handle, int mode, int &err);
35         virtual int STat(const char *path, struct stat *buffer, int &err);
36         virtual char *Tmpnam(char *string, int &err);
37         virtual int Umask(int pmode, int &err);
38         virtual int Unlink(const char *filename, int &err);
39         virtual int Utime(char *filename, struct utimbuf *times, int &err);
40         virtual int Write(int handle, const void *buffer, unsigned int count, int &err);
41
42         inline void SetPerlObj(CPerlObj *p) { pPerl = p; };
43         inline void SetSockCtl(CPerlSock *p) { pSock = p; };
44         inline void SetStdObj(IPerlStdIOWin *p) { pStdIO = p; };
45 protected:
46         inline int IsWin95(void)
47         {
48                 return (os_id() == VER_PLATFORM_WIN32_WINDOWS);
49         };
50         inline int IsWinNT(void)
51         {
52                 return (os_id() == VER_PLATFORM_WIN32_NT);
53         };
54         int GetOSfhandle(int filenum)
55         {
56                 return pStdIO->GetOSfhandle(filenum);
57         };
58         DWORD os_id(void)
59         {
60                 if((-1) == w32_platform)
61                 {
62                         OSVERSIONINFO osver;
63
64                         memset(&osver, 0, sizeof(OSVERSIONINFO));
65                         osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
66                         GetVersionEx(&osver);
67                         w32_platform = osver.dwPlatformId;
68                 }
69                 return (w32_platform);
70         }
71
72         DWORD w32_platform;
73         CPerlObj *pPerl;
74         CPerlSock *pSock;
75         IPerlStdIOWin *pStdIO;
76 };
77
78 #define CALLFUNCRET(x)\
79         int ret = x;\
80         if(ret)\
81                 err = errno;\
82         return ret;
83
84 #define CALLFUNCERR(x)\
85         int ret = x;\
86         if(errno)\
87                 err = errno;\
88         return ret;
89
90 #define LCALLFUNCERR(x)\
91         long ret = x;\
92         if(errno)\
93                 err = errno;\
94         return ret;
95
96 int CPerlLIO::Access(const char *path, int mode, int &err)
97 {
98         CALLFUNCRET(access(path, mode))
99 }
100
101 int CPerlLIO::Chmod(const char *filename, int pmode, int &err)
102 {
103         CALLFUNCRET(chmod(filename, pmode))
104 }
105
106 int CPerlLIO::Chsize(int handle, long size, int &err)
107 {
108         CALLFUNCRET(chsize(handle, size))
109 }
110
111 int CPerlLIO::Close(int fd, int &err)
112 {
113         CALLFUNCRET(close(fd))
114 }
115
116 int CPerlLIO::Dup(int fd, int &err)
117 {
118         CALLFUNCERR(dup(fd))
119 }
120
121 int CPerlLIO::Dup2(int handle1, int handle2, int &err)
122 {
123         CALLFUNCERR(dup2(handle1, handle2))
124 }
125
126
127 #define LK_ERR(f,i)     ((f) ? (i = 0) : (err = GetLastError()))
128 #define LK_LEN          0xffff0000
129 #define LOCK_SH 1
130 #define LOCK_EX 2
131 #define LOCK_NB 4
132 #define LOCK_UN 8
133
134 int CPerlLIO::Flock(int fd, int oper, int &err)
135 {
136     OVERLAPPED o;
137     int i = -1;
138     HANDLE fh;
139
140     if (!IsWinNT()) {
141         croak("flock() unimplemented on this platform");
142         return -1;
143     }
144     fh = (HANDLE)GetOSfhandle(fd);
145     memset(&o, 0, sizeof(o));
146
147     switch(oper) {
148     case LOCK_SH:               /* shared lock */
149         LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
150         break;
151     case LOCK_EX:               /* exclusive lock */
152         LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
153         break;
154     case LOCK_SH|LOCK_NB:       /* non-blocking shared lock */
155         LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
156         break;
157     case LOCK_EX|LOCK_NB:       /* non-blocking exclusive lock */
158         LK_ERR(LockFileEx(fh,
159                        LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
160                        0, LK_LEN, 0, &o),i);
161         break;
162     case LOCK_UN:               /* unlock lock */
163         LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
164         break;
165     default:                    /* unknown */
166         err = EINVAL;
167         break;
168     }
169     return i;
170 }
171
172 int CPerlLIO::FStat(int fd, struct stat *sbufptr, int &err)
173 {
174         CALLFUNCERR(fstat(fd, sbufptr))
175 }
176
177 int CPerlLIO::IOCtl(int i, unsigned int u, char *data, int &err)
178 {
179         return pSock->IoctlSocket((SOCKET)i, (long)u, (u_long*)data, err);
180 }
181
182 int CPerlLIO::Isatty(int fd, int &err)
183 {
184         return isatty(fd);
185 }
186
187 long CPerlLIO::Lseek(int fd, long offset, int origin, int &err)
188 {
189         LCALLFUNCERR(lseek(fd, offset, origin))
190 }
191
192 int CPerlLIO::Lstat(const char *path, struct stat *sbufptr, int &err)
193 {
194         return STat(path, sbufptr, err);
195 }
196
197 char *CPerlLIO::Mktemp(char *Template, int &err)
198 {
199         return mktemp(Template);
200 }
201
202 int CPerlLIO::Open(const char *filename, int oflag, int &err)
203 {
204         int ret;
205     if(stricmp(filename, "/dev/null") == 0)
206                 ret = open("NUL", oflag);
207         else
208                 ret = open(filename, oflag);
209
210         if(errno)
211                 err = errno;
212         return ret;
213 }
214
215 int CPerlLIO::Open(const char *filename, int oflag, int pmode, int &err)
216 {
217         int ret;
218     if(stricmp(filename, "/dev/null") == 0)
219                 ret = open("NUL", oflag, pmode);
220         else
221                 ret = open(filename, oflag, pmode);
222
223         if(errno)
224                 err = errno;
225         return ret;
226 }
227
228 int CPerlLIO::Read(int fd, void *buffer, unsigned int cnt, int &err)
229 {
230         CALLFUNCERR(read(fd, buffer, cnt))
231 }
232
233 int CPerlLIO::Rename(const char *OldFileName, const char *newname, int &err)
234 {
235         char szNewWorkName[MAX_PATH+1];
236         WIN32_FIND_DATA fdOldFile, fdNewFile;
237         HANDLE handle;
238         char *ptr;
239
240         if((strchr(OldFileName, '\\') || strchr(OldFileName, '/'))
241                 && strchr(newname, '\\') == NULL
242                         && strchr(newname, '/') == NULL)
243         {
244                 strcpy(szNewWorkName, OldFileName);
245                 if((ptr = strrchr(szNewWorkName, '\\')) == NULL)
246                         ptr = strrchr(szNewWorkName, '/');
247                 strcpy(++ptr, newname);
248         }
249         else
250                 strcpy(szNewWorkName, newname);
251
252         if(stricmp(OldFileName, szNewWorkName) != 0)
253         {   // check that we're not being fooled by relative paths
254                 // and only delete the new file
255                 //  1) if it exists
256                 //  2) it is not the same file as the old file
257                 //  3) old file exist
258                 // GetFullPathName does not return the long file name on some systems
259                 handle = FindFirstFile(OldFileName, &fdOldFile);
260                 if(handle != INVALID_HANDLE_VALUE)
261                 {
262                         FindClose(handle);
263         
264                         handle = FindFirstFile(szNewWorkName, &fdNewFile);
265         
266                         if(handle != INVALID_HANDLE_VALUE)
267                                 FindClose(handle);
268                         else
269                                 fdNewFile.cFileName[0] = '\0';
270
271                         if(strcmp(fdOldFile.cAlternateFileName, fdNewFile.cAlternateFileName) != 0
272                                 && strcmp(fdOldFile.cFileName, fdNewFile.cFileName) != 0)
273                         {   // file exists and not same file
274                                 DeleteFile(szNewWorkName);
275                         }
276                 }
277         }
278         int ret = rename(OldFileName, szNewWorkName);
279         if(ret)
280                 err = errno;
281
282         return ret;
283 }
284
285 int CPerlLIO::Setmode(int fd, int mode, int &err)
286 {
287         CALLFUNCRET(setmode(fd, mode))
288 }
289
290 int CPerlLIO::STat(const char *path, struct stat *sbufptr, int &err)
291 {
292     char                t[MAX_PATH]; 
293     const char  *p = path;
294     int         l = strlen(path);
295     int         res;
296
297     if (l > 1) {
298         switch(path[l - 1]) {
299         case '\\':
300         case '/':
301             if (path[l - 2] != ':') {
302                 strncpy(t, path, l - 1);
303                 t[l - 1] = 0;
304                 p = t;
305             };
306         }
307     }
308         res = stat(path, sbufptr);
309 #ifdef __BORLANDC__
310     if (res == 0) {
311         if (S_ISDIR(buffer->st_mode))
312             buffer->st_mode |= S_IWRITE | S_IEXEC;
313         else if (S_ISREG(buffer->st_mode)) {
314             if (l >= 4 && path[l-4] == '.') {
315                 const char *e = path + l - 3;
316                 if (strnicmp(e,"exe",3)
317                     && strnicmp(e,"bat",3)
318                     && strnicmp(e,"com",3)
319                     && (IsWin95() || strnicmp(e,"cmd",3)))
320                     buffer->st_mode &= ~S_IEXEC;
321                 else
322                     buffer->st_mode |= S_IEXEC;
323             }
324             else
325                 buffer->st_mode &= ~S_IEXEC;
326         }
327     }
328 #endif
329     return res;
330 }
331
332 char *CPerlLIO::Tmpnam(char *string, int &err)
333 {
334         return tmpnam(string);
335 }
336
337 int CPerlLIO::Umask(int pmode, int &err)
338 {
339         return umask(pmode);
340 }
341
342 int CPerlLIO::Unlink(const char *filename, int &err)
343 {
344         chmod(filename, _S_IREAD | _S_IWRITE);
345         CALLFUNCRET(unlink(filename))
346 }
347
348 int CPerlLIO::Utime(char *filename, struct utimbuf *times, int &err)
349 {
350         CALLFUNCRET(utime(filename, times))
351 }
352
353 int CPerlLIO::Write(int fd, const void *buffer, unsigned int cnt, int &err)
354 {
355         CALLFUNCERR(write(fd, buffer, cnt))
356 }
357