|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* OS2 IO module |
|
7 * |
|
8 * Assumes synchronous I/O. |
|
9 * |
|
10 */ |
|
11 |
|
12 #include "primpl.h" |
|
13 #include "prio.h" |
|
14 #include <ctype.h> |
|
15 #include <string.h> |
|
16 #include <limits.h> |
|
17 #include <dirent.h> |
|
18 #include <fcntl.h> |
|
19 #include <io.h> |
|
20 |
|
21 struct _MDLock _pr_ioq_lock; |
|
22 |
|
23 static PRBool isWSEB = PR_FALSE; /* whether we are using an OS/2 kernel that supports large files */ |
|
24 |
|
25 typedef APIRET (*DosOpenLType)(PSZ pszFileName, PHFILE pHf, PULONG pulAction, |
|
26 LONGLONG cbFile, ULONG ulAttribute, |
|
27 ULONG fsOpenFlags, ULONG fsOpenMode, |
|
28 PEAOP2 peaop2); |
|
29 |
|
30 typedef APIRET (*DosSetFileLocksLType)(HFILE hFile, PFILELOCKL pflUnlock, |
|
31 PFILELOCKL pflLock, ULONG timeout, |
|
32 ULONG flags); |
|
33 |
|
34 typedef APIRET (*DosSetFilePtrLType)(HFILE hFile, LONGLONG ib, ULONG method, |
|
35 PLONGLONG ibActual); |
|
36 |
|
37 DosOpenLType myDosOpenL; |
|
38 DosSetFileLocksLType myDosSetFileLocksL; |
|
39 DosSetFilePtrLType myDosSetFilePtrL; |
|
40 |
|
41 void |
|
42 _PR_MD_INIT_IO() |
|
43 { |
|
44 APIRET rc; |
|
45 HMODULE module; |
|
46 |
|
47 sock_init(); |
|
48 |
|
49 rc = DosLoadModule(NULL, 0, "DOSCALL1", &module); |
|
50 if (rc != NO_ERROR) |
|
51 { |
|
52 return; |
|
53 } |
|
54 rc = DosQueryProcAddr(module, 981, NULL, (PFN*) &myDosOpenL); |
|
55 if (rc != NO_ERROR) |
|
56 { |
|
57 return; |
|
58 } |
|
59 rc = DosQueryProcAddr(module, 986, NULL, (PFN*) &myDosSetFileLocksL); |
|
60 if (rc != NO_ERROR) |
|
61 { |
|
62 return; |
|
63 } |
|
64 rc = DosQueryProcAddr(module, 988, NULL, (PFN*) &myDosSetFilePtrL); |
|
65 if (rc != NO_ERROR) |
|
66 { |
|
67 return; |
|
68 } |
|
69 isWSEB = PR_TRUE; |
|
70 } |
|
71 |
|
72 PRStatus |
|
73 _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) |
|
74 { |
|
75 PRInt32 rv; |
|
76 ULONG count; |
|
77 |
|
78 PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? |
|
79 SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks); |
|
80 rv = DosWaitEventSem(thread->md.blocked_sema, msecs); |
|
81 DosResetEventSem(thread->md.blocked_sema, &count); |
|
82 switch(rv) |
|
83 { |
|
84 case NO_ERROR: |
|
85 return PR_SUCCESS; |
|
86 break; |
|
87 case ERROR_TIMEOUT: |
|
88 _PR_THREAD_LOCK(thread); |
|
89 if (thread->state == _PR_IO_WAIT) { |
|
90 ; |
|
91 } else { |
|
92 if (thread->wait.cvar != NULL) { |
|
93 thread->wait.cvar = NULL; |
|
94 _PR_THREAD_UNLOCK(thread); |
|
95 } else { |
|
96 /* The CVAR was notified just as the timeout |
|
97 * occurred. This led to us being notified twice. |
|
98 * call SemRequest() to clear the semaphore. |
|
99 */ |
|
100 _PR_THREAD_UNLOCK(thread); |
|
101 rv = DosWaitEventSem(thread->md.blocked_sema, 0); |
|
102 DosResetEventSem(thread->md.blocked_sema, &count); |
|
103 PR_ASSERT(rv == NO_ERROR); |
|
104 } |
|
105 } |
|
106 return PR_SUCCESS; |
|
107 break; |
|
108 default: |
|
109 break; |
|
110 } |
|
111 return PR_FAILURE; |
|
112 } |
|
113 PRStatus |
|
114 _PR_MD_WAKEUP_WAITER(PRThread *thread) |
|
115 { |
|
116 if ( _PR_IS_NATIVE_THREAD(thread) ) |
|
117 { |
|
118 if (DosPostEventSem(thread->md.blocked_sema) != NO_ERROR) |
|
119 return PR_FAILURE; |
|
120 else |
|
121 return PR_SUCCESS; |
|
122 } |
|
123 } |
|
124 |
|
125 |
|
126 /* --- FILE IO ----------------------------------------------------------- */ |
|
127 /* |
|
128 * _PR_MD_OPEN() -- Open a file |
|
129 * |
|
130 * returns: a fileHandle |
|
131 * |
|
132 * The NSPR open flags (osflags) are translated into flags for OS/2 |
|
133 * |
|
134 * Mode seems to be passed in as a unix style file permissions argument |
|
135 * as in 0666, in the case of opening the logFile. |
|
136 * |
|
137 */ |
|
138 PRInt32 |
|
139 _PR_MD_OPEN(const char *name, PRIntn osflags, int mode) |
|
140 { |
|
141 HFILE file; |
|
142 PRInt32 access = OPEN_SHARE_DENYNONE; |
|
143 PRInt32 flags = 0L; |
|
144 APIRET rc = 0; |
|
145 PRUword actionTaken; |
|
146 |
|
147 #ifdef MOZ_OS2_HIGH_MEMORY |
|
148 /* |
|
149 * All the pointer arguments (&file, &actionTaken and name) have to be in |
|
150 * low memory for DosOpen to use them. |
|
151 * The following moves name to low memory. |
|
152 */ |
|
153 if ((ULONG)name >= 0x20000000) |
|
154 { |
|
155 size_t len = strlen(name) + 1; |
|
156 char *copy = (char *)alloca(len); |
|
157 memcpy(copy, name, len); |
|
158 name = copy; |
|
159 } |
|
160 #endif |
|
161 |
|
162 if (osflags & PR_SYNC) access |= OPEN_FLAGS_WRITE_THROUGH; |
|
163 |
|
164 if (osflags & PR_RDONLY) |
|
165 access |= OPEN_ACCESS_READONLY; |
|
166 else if (osflags & PR_WRONLY) |
|
167 access |= OPEN_ACCESS_WRITEONLY; |
|
168 else if(osflags & PR_RDWR) |
|
169 access |= OPEN_ACCESS_READWRITE; |
|
170 |
|
171 if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) |
|
172 { |
|
173 flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS; |
|
174 } |
|
175 else if (osflags & PR_CREATE_FILE) |
|
176 { |
|
177 if (osflags & PR_TRUNCATE) |
|
178 flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; |
|
179 else |
|
180 flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; |
|
181 } |
|
182 else |
|
183 { |
|
184 if (osflags & PR_TRUNCATE) |
|
185 flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; |
|
186 else |
|
187 flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; |
|
188 } |
|
189 |
|
190 do { |
|
191 if (isWSEB) |
|
192 { |
|
193 rc = myDosOpenL((char*)name, |
|
194 &file, /* file handle if successful */ |
|
195 &actionTaken, /* reason for failure */ |
|
196 0, /* initial size of new file */ |
|
197 FILE_NORMAL, /* file system attributes */ |
|
198 flags, /* Open flags */ |
|
199 access, /* Open mode and rights */ |
|
200 0); /* OS/2 Extended Attributes */ |
|
201 } |
|
202 else |
|
203 { |
|
204 rc = DosOpen((char*)name, |
|
205 &file, /* file handle if successful */ |
|
206 &actionTaken, /* reason for failure */ |
|
207 0, /* initial size of new file */ |
|
208 FILE_NORMAL, /* file system attributes */ |
|
209 flags, /* Open flags */ |
|
210 access, /* Open mode and rights */ |
|
211 0); /* OS/2 Extended Attributes */ |
|
212 }; |
|
213 if (rc == ERROR_TOO_MANY_OPEN_FILES) { |
|
214 ULONG CurMaxFH = 0; |
|
215 LONG ReqCount = 20; |
|
216 APIRET rc2; |
|
217 rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH); |
|
218 if (rc2 != NO_ERROR) { |
|
219 break; |
|
220 } |
|
221 } |
|
222 } while (rc == ERROR_TOO_MANY_OPEN_FILES); |
|
223 |
|
224 if (rc != NO_ERROR) { |
|
225 _PR_MD_MAP_OPEN_ERROR(rc); |
|
226 return -1; |
|
227 } |
|
228 |
|
229 return (PRInt32)file; |
|
230 } |
|
231 |
|
232 PRInt32 |
|
233 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) |
|
234 { |
|
235 ULONG bytes; |
|
236 int rv; |
|
237 |
|
238 rv = DosRead((HFILE)fd->secret->md.osfd, |
|
239 (PVOID)buf, |
|
240 len, |
|
241 &bytes); |
|
242 |
|
243 if (rv != NO_ERROR) |
|
244 { |
|
245 /* ERROR_HANDLE_EOF can only be returned by async io */ |
|
246 PR_ASSERT(rv != ERROR_HANDLE_EOF); |
|
247 if (rv == ERROR_BROKEN_PIPE) |
|
248 return 0; |
|
249 else { |
|
250 _PR_MD_MAP_READ_ERROR(rv); |
|
251 return -1; |
|
252 } |
|
253 } |
|
254 return (PRInt32)bytes; |
|
255 } |
|
256 |
|
257 PRInt32 |
|
258 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) |
|
259 { |
|
260 PRInt32 bytes; |
|
261 int rv; |
|
262 |
|
263 rv = DosWrite((HFILE)fd->secret->md.osfd, |
|
264 (PVOID)buf, |
|
265 len, |
|
266 (PULONG)&bytes); |
|
267 |
|
268 if (rv != NO_ERROR) |
|
269 { |
|
270 _PR_MD_MAP_WRITE_ERROR(rv); |
|
271 return -1; |
|
272 } |
|
273 |
|
274 if (len != bytes) { |
|
275 rv = ERROR_DISK_FULL; |
|
276 _PR_MD_MAP_WRITE_ERROR(rv); |
|
277 return -1; |
|
278 } |
|
279 |
|
280 return bytes; |
|
281 } /* --- end _PR_MD_WRITE() --- */ |
|
282 |
|
283 PRInt32 |
|
284 _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) |
|
285 { |
|
286 PRInt32 rv; |
|
287 PRUword newLocation; |
|
288 |
|
289 rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation); |
|
290 |
|
291 if (rv != NO_ERROR) { |
|
292 _PR_MD_MAP_LSEEK_ERROR(rv); |
|
293 return -1; |
|
294 } else |
|
295 return newLocation; |
|
296 } |
|
297 |
|
298 PRInt64 |
|
299 _PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) |
|
300 { |
|
301 #ifdef NO_LONG_LONG |
|
302 PRInt64 result; |
|
303 PRInt32 rv, low = offset.lo, hi = offset.hi; |
|
304 PRUword newLocation; |
|
305 |
|
306 rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation); |
|
307 rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation); |
|
308 |
|
309 if (rv != NO_ERROR) { |
|
310 _PR_MD_MAP_LSEEK_ERROR(rv); |
|
311 hi = newLocation = -1; |
|
312 } |
|
313 |
|
314 result.lo = newLocation; |
|
315 result.hi = hi; |
|
316 return result; |
|
317 |
|
318 #else |
|
319 PRInt32 where, rc, lo = (PRInt32)offset, hi = (PRInt32)(offset >> 32); |
|
320 PRUint64 rv; |
|
321 PRUint32 newLocation, uhi; |
|
322 PRUint64 newLocationL; |
|
323 |
|
324 switch (whence) |
|
325 { |
|
326 case PR_SEEK_SET: |
|
327 where = FILE_BEGIN; |
|
328 break; |
|
329 case PR_SEEK_CUR: |
|
330 where = FILE_CURRENT; |
|
331 break; |
|
332 case PR_SEEK_END: |
|
333 where = FILE_END; |
|
334 break; |
|
335 default: |
|
336 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
|
337 return -1; |
|
338 } |
|
339 if (isWSEB) |
|
340 { |
|
341 rc = myDosSetFilePtrL((HFILE)fd->secret->md.osfd, offset, where, (PLONGLONG)&newLocationL); |
|
342 } |
|
343 else |
|
344 { |
|
345 rc = DosSetFilePtr((HFILE)fd->secret->md.osfd, lo, where, (PULONG)&newLocation); |
|
346 } |
|
347 |
|
348 if (rc != NO_ERROR) { |
|
349 _PR_MD_MAP_LSEEK_ERROR(rc); |
|
350 return -1; |
|
351 } |
|
352 |
|
353 if (isWSEB) |
|
354 { |
|
355 return newLocationL; |
|
356 } |
|
357 |
|
358 uhi = (PRUint32)hi; |
|
359 PR_ASSERT((PRInt32)uhi >= 0); |
|
360 rv = uhi; |
|
361 PR_ASSERT((PRInt64)rv >= 0); |
|
362 rv = (rv << 32); |
|
363 PR_ASSERT((PRInt64)rv >= 0); |
|
364 rv += newLocation; |
|
365 PR_ASSERT((PRInt64)rv >= 0); |
|
366 return (PRInt64)rv; |
|
367 #endif |
|
368 } |
|
369 |
|
370 PRInt32 |
|
371 _PR_MD_FSYNC(PRFileDesc *fd) |
|
372 { |
|
373 PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd); |
|
374 |
|
375 if (rc != NO_ERROR) { |
|
376 if (rc != ERROR_ACCESS_DENIED) { |
|
377 _PR_MD_MAP_FSYNC_ERROR(rc); |
|
378 return -1; |
|
379 } |
|
380 } |
|
381 return 0; |
|
382 } |
|
383 |
|
384 PRInt32 |
|
385 _MD_CloseFile(PRInt32 osfd) |
|
386 { |
|
387 PRInt32 rv; |
|
388 |
|
389 rv = DosClose((HFILE)osfd); |
|
390 if (rv != NO_ERROR) |
|
391 _PR_MD_MAP_CLOSE_ERROR(rv); |
|
392 return rv; |
|
393 } |
|
394 |
|
395 |
|
396 /* --- DIR IO ------------------------------------------------------------ */ |
|
397 #define GetFileFromDIR(d) (isWSEB?(d)->d_entry.large.achName:(d)->d_entry.small.achName) |
|
398 #define GetFileAttr(d) (isWSEB?(d)->d_entry.large.attrFile:(d)->d_entry.small.attrFile) |
|
399 |
|
400 void FlipSlashes(char *cp, int len) |
|
401 { |
|
402 while (--len >= 0) { |
|
403 if (cp[0] == '/') { |
|
404 cp[0] = PR_DIRECTORY_SEPARATOR; |
|
405 } |
|
406 cp++; |
|
407 } |
|
408 } |
|
409 |
|
410 /* |
|
411 ** |
|
412 ** Local implementations of standard Unix RTL functions which are not provided |
|
413 ** by the VAC RTL. |
|
414 ** |
|
415 */ |
|
416 |
|
417 PRInt32 |
|
418 _PR_MD_CLOSE_DIR(_MDDir *d) |
|
419 { |
|
420 PRInt32 rc; |
|
421 |
|
422 if ( d ) { |
|
423 rc = DosFindClose(d->d_hdl); |
|
424 if(rc == NO_ERROR){ |
|
425 d->magic = (PRUint32)-1; |
|
426 return PR_SUCCESS; |
|
427 } else { |
|
428 _PR_MD_MAP_CLOSEDIR_ERROR(rc); |
|
429 return PR_FAILURE; |
|
430 } |
|
431 } |
|
432 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
|
433 return PR_FAILURE; |
|
434 } |
|
435 |
|
436 |
|
437 PRStatus |
|
438 _PR_MD_OPEN_DIR(_MDDir *d, const char *name) |
|
439 { |
|
440 char filename[ CCHMAXPATH ]; |
|
441 PRUword numEntries, rc; |
|
442 |
|
443 numEntries = 1; |
|
444 |
|
445 PR_snprintf(filename, CCHMAXPATH, "%s%s%s", |
|
446 name, PR_DIRECTORY_SEPARATOR_STR, "*.*"); |
|
447 FlipSlashes( filename, strlen(filename) ); |
|
448 |
|
449 d->d_hdl = HDIR_CREATE; |
|
450 |
|
451 if (isWSEB) |
|
452 { |
|
453 rc = DosFindFirst( filename, |
|
454 &d->d_hdl, |
|
455 FILE_DIRECTORY | FILE_HIDDEN, |
|
456 &(d->d_entry.large), |
|
457 sizeof(d->d_entry.large), |
|
458 &numEntries, |
|
459 FIL_STANDARDL); |
|
460 } |
|
461 else |
|
462 { |
|
463 rc = DosFindFirst( filename, |
|
464 &d->d_hdl, |
|
465 FILE_DIRECTORY | FILE_HIDDEN, |
|
466 &(d->d_entry.small), |
|
467 sizeof(d->d_entry.small), |
|
468 &numEntries, |
|
469 FIL_STANDARD); |
|
470 } |
|
471 if ( rc != NO_ERROR ) { |
|
472 _PR_MD_MAP_OPENDIR_ERROR(rc); |
|
473 return PR_FAILURE; |
|
474 } |
|
475 d->firstEntry = PR_TRUE; |
|
476 d->magic = _MD_MAGIC_DIR; |
|
477 return PR_SUCCESS; |
|
478 } |
|
479 |
|
480 char * |
|
481 _PR_MD_READ_DIR(_MDDir *d, PRIntn flags) |
|
482 { |
|
483 PRUword numFiles = 1; |
|
484 BOOL rv; |
|
485 char *fileName; |
|
486 USHORT fileAttr; |
|
487 |
|
488 if ( d ) { |
|
489 while (1) { |
|
490 if (d->firstEntry) { |
|
491 d->firstEntry = PR_FALSE; |
|
492 rv = NO_ERROR; |
|
493 } else { |
|
494 rv = DosFindNext(d->d_hdl, |
|
495 &(d->d_entry), |
|
496 sizeof(d->d_entry), |
|
497 &numFiles); |
|
498 } |
|
499 if (rv != NO_ERROR) { |
|
500 break; |
|
501 } |
|
502 fileName = GetFileFromDIR(d); |
|
503 fileAttr = GetFileAttr(d); |
|
504 if ( (flags & PR_SKIP_DOT) && |
|
505 (fileName[0] == '.') && (fileName[1] == '\0')) |
|
506 continue; |
|
507 if ( (flags & PR_SKIP_DOT_DOT) && |
|
508 (fileName[0] == '.') && (fileName[1] == '.') && |
|
509 (fileName[2] == '\0')) |
|
510 continue; |
|
511 /* |
|
512 * XXX |
|
513 * Is this the correct definition of a hidden file on OS/2? |
|
514 */ |
|
515 if ((flags & PR_SKIP_NONE) && (fileAttr & FILE_HIDDEN)) |
|
516 return fileName; |
|
517 else if ((flags & PR_SKIP_HIDDEN) && (fileAttr & FILE_HIDDEN)) |
|
518 continue; |
|
519 return fileName; |
|
520 } |
|
521 PR_ASSERT(NO_ERROR != rv); |
|
522 _PR_MD_MAP_READDIR_ERROR(rv); |
|
523 return NULL; |
|
524 } |
|
525 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
|
526 return NULL; |
|
527 } |
|
528 |
|
529 PRInt32 |
|
530 _PR_MD_DELETE(const char *name) |
|
531 { |
|
532 PRInt32 rc = DosDelete((char*)name); |
|
533 if(rc == NO_ERROR) { |
|
534 return 0; |
|
535 } else { |
|
536 _PR_MD_MAP_DELETE_ERROR(rc); |
|
537 return -1; |
|
538 } |
|
539 } |
|
540 |
|
541 PRInt32 |
|
542 _PR_MD_STAT(const char *fn, struct stat *info) |
|
543 { |
|
544 PRInt32 rv; |
|
545 char filename[CCHMAXPATH]; |
|
546 |
|
547 PR_snprintf(filename, CCHMAXPATH, "%s", fn); |
|
548 FlipSlashes(filename, strlen(filename)); |
|
549 |
|
550 rv = _stat((char*)filename, info); |
|
551 if (-1 == rv) { |
|
552 /* |
|
553 * Check for MSVC runtime library _stat() bug. |
|
554 * (It's really a bug in FindFirstFile().) |
|
555 * If a pathname ends in a backslash or slash, |
|
556 * e.g., c:\temp\ or c:/temp/, _stat() will fail. |
|
557 * Note: a pathname ending in a slash (e.g., c:/temp/) |
|
558 * can be handled by _stat() on NT but not on Win95. |
|
559 * |
|
560 * We remove the backslash or slash at the end and |
|
561 * try again. |
|
562 * |
|
563 * Not sure if this happens on OS/2 or not, |
|
564 * but it doesn't hurt to be careful. |
|
565 */ |
|
566 |
|
567 int len = strlen(fn); |
|
568 if (len > 0 && len <= _MAX_PATH |
|
569 && (fn[len - 1] == '\\' || fn[len - 1] == '/')) { |
|
570 char newfn[_MAX_PATH + 1]; |
|
571 |
|
572 strcpy(newfn, fn); |
|
573 newfn[len - 1] = '\0'; |
|
574 rv = _stat(newfn, info); |
|
575 } |
|
576 } |
|
577 |
|
578 if (-1 == rv) { |
|
579 _PR_MD_MAP_STAT_ERROR(errno); |
|
580 } |
|
581 return rv; |
|
582 } |
|
583 |
|
584 PRInt32 |
|
585 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) |
|
586 { |
|
587 struct stat sb; |
|
588 PRInt32 rv; |
|
589 PRInt64 s, s2us; |
|
590 |
|
591 if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) { |
|
592 if (info) { |
|
593 if (S_IFREG & sb.st_mode) |
|
594 info->type = PR_FILE_FILE ; |
|
595 else if (S_IFDIR & sb.st_mode) |
|
596 info->type = PR_FILE_DIRECTORY; |
|
597 else |
|
598 info->type = PR_FILE_OTHER; |
|
599 info->size = sb.st_size; |
|
600 LL_I2L(s2us, PR_USEC_PER_SEC); |
|
601 LL_I2L(s, sb.st_mtime); |
|
602 LL_MUL(s, s, s2us); |
|
603 info->modifyTime = s; |
|
604 LL_I2L(s, sb.st_ctime); |
|
605 LL_MUL(s, s, s2us); |
|
606 info->creationTime = s; |
|
607 } |
|
608 } |
|
609 return rv; |
|
610 } |
|
611 |
|
612 PRInt32 |
|
613 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) |
|
614 { |
|
615 PRFileInfo info32; |
|
616 PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32); |
|
617 if (rv != 0) |
|
618 { |
|
619 return rv; |
|
620 } |
|
621 info->type = info32.type; |
|
622 LL_UI2L(info->size,info32.size); |
|
623 info->modifyTime = info32.modifyTime; |
|
624 info->creationTime = info32.creationTime; |
|
625 |
|
626 if (isWSEB) |
|
627 { |
|
628 APIRET rc ; |
|
629 FILESTATUS3L fstatus; |
|
630 |
|
631 rc = DosQueryPathInfo(fn, FIL_STANDARDL, &fstatus, sizeof(fstatus)); |
|
632 |
|
633 if (NO_ERROR != rc) |
|
634 { |
|
635 _PR_MD_MAP_OPEN_ERROR(rc); |
|
636 return -1; |
|
637 } |
|
638 |
|
639 if (! (fstatus.attrFile & FILE_DIRECTORY)) |
|
640 { |
|
641 info->size = fstatus.cbFile; |
|
642 } |
|
643 } |
|
644 |
|
645 return rv; |
|
646 } |
|
647 |
|
648 PRInt32 |
|
649 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) |
|
650 { |
|
651 /* For once, the VAC compiler/library did a nice thing. |
|
652 * The file handle used by the C runtime is the same one |
|
653 * returned by the OS when you call DosOpen(). This means |
|
654 * that you can take an OS HFILE and use it with C file |
|
655 * functions. The only caveat is that you have to call |
|
656 * _setmode() first to initialize some junk. This is |
|
657 * immensely useful because I did not have a clue how to |
|
658 * implement this function otherwise. The windows folks |
|
659 * took the source from the Microsoft C library source, but |
|
660 * IBM wasn't kind enough to ship the source with VAC. |
|
661 * On second thought, the needed function could probably |
|
662 * be gotten from the OS/2 GNU library source, but the |
|
663 * point is now moot. |
|
664 */ |
|
665 struct stat hinfo; |
|
666 PRInt64 s, s2us; |
|
667 |
|
668 _setmode(fd->secret->md.osfd, O_BINARY); |
|
669 if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) { |
|
670 _PR_MD_MAP_FSTAT_ERROR(errno); |
|
671 return -1; |
|
672 } |
|
673 |
|
674 if (hinfo.st_mode & S_IFDIR) |
|
675 info->type = PR_FILE_DIRECTORY; |
|
676 else |
|
677 info->type = PR_FILE_FILE; |
|
678 |
|
679 info->size = hinfo.st_size; |
|
680 LL_I2L(s2us, PR_USEC_PER_SEC); |
|
681 LL_I2L(s, hinfo.st_mtime); |
|
682 LL_MUL(s, s, s2us); |
|
683 info->modifyTime = s; |
|
684 LL_I2L(s, hinfo.st_ctime); |
|
685 LL_MUL(s, s, s2us); |
|
686 info->creationTime = s; |
|
687 |
|
688 return 0; |
|
689 } |
|
690 |
|
691 PRInt32 |
|
692 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) |
|
693 { |
|
694 PRFileInfo info32; |
|
695 PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32); |
|
696 if (0 == rv) |
|
697 { |
|
698 info->type = info32.type; |
|
699 LL_UI2L(info->size,info32.size); |
|
700 |
|
701 info->modifyTime = info32.modifyTime; |
|
702 info->creationTime = info32.creationTime; |
|
703 } |
|
704 |
|
705 if (isWSEB) |
|
706 { |
|
707 APIRET rc ; |
|
708 FILESTATUS3L fstatus; |
|
709 |
|
710 rc = DosQueryFileInfo(fd->secret->md.osfd, FIL_STANDARDL, &fstatus, sizeof(fstatus)); |
|
711 |
|
712 if (NO_ERROR != rc) |
|
713 { |
|
714 _PR_MD_MAP_OPEN_ERROR(rc); |
|
715 return -1; |
|
716 } |
|
717 |
|
718 if (! (fstatus.attrFile & FILE_DIRECTORY)) |
|
719 { |
|
720 info->size = fstatus.cbFile; |
|
721 } |
|
722 } |
|
723 |
|
724 return rv; |
|
725 } |
|
726 |
|
727 |
|
728 PRInt32 |
|
729 _PR_MD_RENAME(const char *from, const char *to) |
|
730 { |
|
731 PRInt32 rc; |
|
732 /* Does this work with dot-relative pathnames? */ |
|
733 if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) { |
|
734 return 0; |
|
735 } else { |
|
736 _PR_MD_MAP_RENAME_ERROR(rc); |
|
737 return -1; |
|
738 } |
|
739 } |
|
740 |
|
741 PRInt32 |
|
742 _PR_MD_ACCESS(const char *name, PRAccessHow how) |
|
743 { |
|
744 PRInt32 rv; |
|
745 switch (how) { |
|
746 case PR_ACCESS_WRITE_OK: |
|
747 rv = access(name, 02); |
|
748 break; |
|
749 case PR_ACCESS_READ_OK: |
|
750 rv = access(name, 04); |
|
751 break; |
|
752 case PR_ACCESS_EXISTS: |
|
753 return access(name, 00); |
|
754 break; |
|
755 default: |
|
756 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
|
757 return -1; |
|
758 } |
|
759 if (rv < 0) |
|
760 _PR_MD_MAP_ACCESS_ERROR(errno); |
|
761 return rv; |
|
762 } |
|
763 |
|
764 PRInt32 |
|
765 _PR_MD_MKDIR(const char *name, PRIntn mode) |
|
766 { |
|
767 PRInt32 rc; |
|
768 /* XXXMB - how to translate the "mode"??? */ |
|
769 if ((rc = DosCreateDir((char *)name, NULL))== NO_ERROR) { |
|
770 return 0; |
|
771 } else { |
|
772 _PR_MD_MAP_MKDIR_ERROR(rc); |
|
773 return -1; |
|
774 } |
|
775 } |
|
776 |
|
777 PRInt32 |
|
778 _PR_MD_RMDIR(const char *name) |
|
779 { |
|
780 PRInt32 rc; |
|
781 if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) { |
|
782 return 0; |
|
783 } else { |
|
784 _PR_MD_MAP_RMDIR_ERROR(rc); |
|
785 return -1; |
|
786 } |
|
787 } |
|
788 |
|
789 PRStatus |
|
790 _PR_MD_LOCKFILE(PRInt32 f) |
|
791 { |
|
792 PRInt32 rv; |
|
793 FILELOCK lock, unlock; |
|
794 FILELOCKL lockL, unlockL; |
|
795 |
|
796 lock.lOffset = 0; |
|
797 lockL.lOffset = 0; |
|
798 lock.lRange = 0xffffffff; |
|
799 lockL.lRange = 0xffffffffffffffff; |
|
800 unlock.lOffset = 0; |
|
801 unlock.lRange = 0; |
|
802 unlockL.lOffset = 0; |
|
803 unlockL.lRange = 0; |
|
804 |
|
805 /* |
|
806 * loop trying to DosSetFileLocks(), |
|
807 * pause for a few miliseconds when can't get the lock |
|
808 * and try again |
|
809 */ |
|
810 for( rv = FALSE; rv == FALSE; /* do nothing */ ) |
|
811 { |
|
812 if (isWSEB) |
|
813 { |
|
814 rv = myDosSetFileLocksL( (HFILE) f, |
|
815 &unlockL, &lockL, |
|
816 0, 0); |
|
817 } |
|
818 else |
|
819 { |
|
820 rv = DosSetFileLocks( (HFILE) f, |
|
821 &unlock, &lock, |
|
822 0, 0); |
|
823 } |
|
824 if ( rv != NO_ERROR ) |
|
825 { |
|
826 DosSleep( 50 ); /* Sleep() a few milisecs and try again. */ |
|
827 } |
|
828 } /* end for() */ |
|
829 return PR_SUCCESS; |
|
830 } /* end _PR_MD_LOCKFILE() */ |
|
831 |
|
832 PRStatus |
|
833 _PR_MD_TLOCKFILE(PRInt32 f) |
|
834 { |
|
835 return _PR_MD_LOCKFILE(f); |
|
836 } /* end _PR_MD_TLOCKFILE() */ |
|
837 |
|
838 |
|
839 PRStatus |
|
840 _PR_MD_UNLOCKFILE(PRInt32 f) |
|
841 { |
|
842 PRInt32 rv; |
|
843 FILELOCK lock, unlock; |
|
844 FILELOCKL lockL, unlockL; |
|
845 |
|
846 lock.lOffset = 0; |
|
847 lockL.lOffset = 0; |
|
848 lock.lRange = 0; |
|
849 lockL.lRange = 0; |
|
850 unlock.lOffset = 0; |
|
851 unlockL.lOffset = 0; |
|
852 unlock.lRange = 0xffffffff; |
|
853 unlockL.lRange = 0xffffffffffffffff; |
|
854 |
|
855 if (isWSEB) |
|
856 { |
|
857 rv = myDosSetFileLocksL( (HFILE) f, |
|
858 &unlockL, &lockL, |
|
859 0, 0); |
|
860 } |
|
861 else |
|
862 { |
|
863 rv = DosSetFileLocks( (HFILE) f, |
|
864 &unlock, &lock, |
|
865 0, 0); |
|
866 } |
|
867 |
|
868 if ( rv != NO_ERROR ) |
|
869 { |
|
870 return PR_SUCCESS; |
|
871 } |
|
872 else |
|
873 { |
|
874 return PR_FAILURE; |
|
875 } |
|
876 } /* end _PR_MD_UNLOCKFILE() */ |
|
877 |
|
878 PRStatus |
|
879 _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) |
|
880 { |
|
881 APIRET rc = 0; |
|
882 ULONG flags; |
|
883 switch (fd->methods->file_type) |
|
884 { |
|
885 case PR_DESC_PIPE: |
|
886 case PR_DESC_FILE: |
|
887 rc = DosQueryFHState((HFILE)fd->secret->md.osfd, &flags); |
|
888 if (rc != NO_ERROR) { |
|
889 PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); |
|
890 return PR_FAILURE; |
|
891 } |
|
892 |
|
893 if (inheritable) |
|
894 flags &= ~OPEN_FLAGS_NOINHERIT; |
|
895 else |
|
896 flags |= OPEN_FLAGS_NOINHERIT; |
|
897 |
|
898 /* Mask off flags DosSetFHState don't want. */ |
|
899 flags &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT); |
|
900 rc = DosSetFHState((HFILE)fd->secret->md.osfd, flags); |
|
901 if (rc != NO_ERROR) { |
|
902 PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); |
|
903 return PR_FAILURE; |
|
904 } |
|
905 break; |
|
906 |
|
907 case PR_DESC_LAYERED: |
|
908 /* what to do here? */ |
|
909 PR_SetError(PR_UNKNOWN_ERROR, 87 /*ERROR_INVALID_PARAMETER*/); |
|
910 return PR_FAILURE; |
|
911 |
|
912 case PR_DESC_SOCKET_TCP: |
|
913 case PR_DESC_SOCKET_UDP: |
|
914 /* These are global on OS/2. */ |
|
915 break; |
|
916 } |
|
917 |
|
918 return PR_SUCCESS; |
|
919 } |
|
920 |
|
921 void |
|
922 _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) |
|
923 { |
|
924 /* XXX this function needs to be implemented */ |
|
925 fd->secret->inheritable = _PR_TRI_UNKNOWN; |
|
926 } |
|
927 |
|
928 void |
|
929 _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) |
|
930 { |
|
931 /* XXX this function needs to be reviewed */ |
|
932 ULONG flags; |
|
933 |
|
934 PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); |
|
935 if (DosQueryFHState((HFILE)fd->secret->md.osfd, &flags) == 0) { |
|
936 if (flags & OPEN_FLAGS_NOINHERIT) { |
|
937 fd->secret->inheritable = _PR_TRI_FALSE; |
|
938 } else { |
|
939 fd->secret->inheritable = _PR_TRI_TRUE; |
|
940 } |
|
941 } |
|
942 } |