~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/md/windows/w95io.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* 
 
3
 * The contents of this file are subject to the Mozilla Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/MPL/
 
7
 * 
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 * 
 
13
 * The Original Code is the Netscape Portable Runtime (NSPR).
 
14
 * 
 
15
 * The Initial Developer of the Original Code is Netscape
 
16
 * Communications Corporation.  Portions created by Netscape are 
 
17
 * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
 
18
 * Rights Reserved.
 
19
 * 
 
20
 * Contributor(s):
 
21
 * 
 
22
 * Alternatively, the contents of this file may be used under the
 
23
 * terms of the GNU General Public License Version 2 or later (the
 
24
 * "GPL"), in which case the provisions of the GPL are applicable 
 
25
 * instead of those above.  If you wish to allow use of your 
 
26
 * version of this file only under the terms of the GPL and not to
 
27
 * allow others to use your version of this file under the MPL,
 
28
 * indicate your decision by deleting the provisions above and
 
29
 * replace them with the notice and other provisions required by
 
30
 * the GPL.  If you do not delete the provisions above, a recipient
 
31
 * may use your version of this file under either the MPL or the
 
32
 * GPL.
 
33
 */
 
34
 
 
35
/* Windows 95 IO module
 
36
 *
 
37
 * Assumes synchronous I/O.
 
38
 *
 
39
 */
 
40
 
 
41
#include "primpl.h"
 
42
#include <direct.h>
 
43
#include <mbstring.h>
 
44
#ifdef MOZ_UNICODE
 
45
#include <wchar.h>
 
46
#endif /* MOZ_UNICODE */
 
47
 
 
48
 
 
49
struct _MDLock               _pr_ioq_lock;
 
50
 
 
51
/*
 
52
 * NSPR-to-NT access right mapping table for files.
 
53
 */
 
54
static DWORD fileAccessTable[] = {
 
55
    FILE_GENERIC_READ,
 
56
    FILE_GENERIC_WRITE,
 
57
    FILE_GENERIC_EXECUTE
 
58
};
 
59
 
 
60
/*
 
61
 * NSPR-to-NT access right mapping table for directories.
 
62
 */
 
63
static DWORD dirAccessTable[] = {
 
64
    FILE_GENERIC_READ,
 
65
    FILE_GENERIC_WRITE|FILE_DELETE_CHILD,
 
66
    FILE_GENERIC_EXECUTE
 
67
};
 
68
 
 
69
/*
 
70
 * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME.
 
71
 * We store the value in a PRTime variable for convenience.
 
72
 * This constant is used by _PR_FileTimeToPRTime().
 
73
 */
 
74
#if defined(__MINGW32__)
 
75
static const PRTime _pr_filetime_offset = 116444736000000000LL;
 
76
#else
 
77
static const PRTime _pr_filetime_offset = 116444736000000000i64;
 
78
#endif
 
79
 
 
80
#ifdef MOZ_UNICODE
 
81
static void InitUnicodeSupport(void);
 
82
#endif
 
83
 
 
84
void
 
85
_PR_MD_INIT_IO()
 
86
{
 
87
    WORD WSAVersion = 0x0101;
 
88
    WSADATA WSAData;
 
89
    int err;
 
90
 
 
91
    err = WSAStartup( WSAVersion, &WSAData );
 
92
    PR_ASSERT(0 == err);
 
93
 
 
94
#ifdef DEBUG
 
95
    /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */
 
96
    {
 
97
        SYSTEMTIME systime;
 
98
        union {
 
99
           PRTime prt;
 
100
           FILETIME ft;
 
101
        } filetime;
 
102
        BOOL rv;
 
103
 
 
104
        systime.wYear = 1970;
 
105
        systime.wMonth = 1;
 
106
        /* wDayOfWeek is ignored */
 
107
        systime.wDay = 1;
 
108
        systime.wHour = 0;
 
109
        systime.wMinute = 0;
 
110
        systime.wSecond = 0;
 
111
        systime.wMilliseconds = 0;
 
112
 
 
113
        rv = SystemTimeToFileTime(&systime, &filetime.ft);
 
114
        PR_ASSERT(0 != rv);
 
115
        PR_ASSERT(filetime.prt == _pr_filetime_offset);
 
116
    }
 
117
#endif /* DEBUG */
 
118
 
 
119
    _PR_NT_InitSids();
 
120
 
 
121
#ifdef MOZ_UNICODE
 
122
    InitUnicodeSupport();
 
123
#endif
 
124
}
 
125
 
 
126
PRStatus
 
127
_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
 
128
{
 
129
    DWORD rv;
 
130
 
 
131
    PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
 
132
        INFINITE : PR_IntervalToMilliseconds(ticks);
 
133
    rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
 
134
    switch(rv) 
 
135
    {
 
136
        case WAIT_OBJECT_0:
 
137
            return PR_SUCCESS;
 
138
            break;
 
139
        case WAIT_TIMEOUT:
 
140
            _PR_THREAD_LOCK(thread);
 
141
            if (thread->state == _PR_IO_WAIT) {
 
142
                          ;
 
143
            } else {
 
144
                if (thread->wait.cvar != NULL) {
 
145
                    thread->wait.cvar = NULL;
 
146
                    _PR_THREAD_UNLOCK(thread);
 
147
                } else {
 
148
                    /* The CVAR was notified just as the timeout
 
149
                     * occurred.  This led to us being notified twice.
 
150
                     * call WaitForSingleObject() to clear the semaphore.
 
151
                     */
 
152
                    _PR_THREAD_UNLOCK(thread);
 
153
                    rv = WaitForSingleObject(thread->md.blocked_sema, 0);
 
154
                    PR_ASSERT(rv == WAIT_OBJECT_0);
 
155
                }
 
156
            }
 
157
            return PR_SUCCESS;
 
158
            break;
 
159
        default:
 
160
            return PR_FAILURE;
 
161
            break;
 
162
    }
 
163
}
 
164
PRStatus
 
165
_PR_MD_WAKEUP_WAITER(PRThread *thread)
 
166
{
 
167
    if ( _PR_IS_NATIVE_THREAD(thread) ) 
 
168
    {
 
169
        if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE)
 
170
            return PR_FAILURE;
 
171
        else
 
172
                        return PR_SUCCESS;
 
173
        }
 
174
}
 
175
 
 
176
 
 
177
/* --- FILE IO ----------------------------------------------------------- */
 
178
/*
 
179
 *  _PR_MD_OPEN() -- Open a file
 
180
 *
 
181
 *  returns: a fileHandle
 
182
 *
 
183
 *  The NSPR open flags (osflags) are translated into flags for Win95
 
184
 *
 
185
 *  Mode seems to be passed in as a unix style file permissions argument
 
186
 *  as in 0666, in the case of opening the logFile. 
 
187
 *
 
188
 */
 
189
PRInt32
 
190
_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
 
191
{
 
192
    HANDLE file;
 
193
    PRInt32 access = 0;
 
194
    PRInt32 flags = 0;
 
195
    PRInt32 flag6 = 0;
 
196
    
 
197
    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
 
198
 
 
199
    if (osflags & PR_RDONLY || osflags & PR_RDWR)
 
200
        access |= GENERIC_READ;
 
201
    if (osflags & PR_WRONLY || osflags & PR_RDWR)
 
202
        access |= GENERIC_WRITE;
 
203
 
 
204
    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
 
205
        flags = CREATE_NEW;
 
206
    else if (osflags & PR_CREATE_FILE) {
 
207
        if (osflags & PR_TRUNCATE)
 
208
            flags = CREATE_ALWAYS;
 
209
        else
 
210
            flags = OPEN_ALWAYS;
 
211
    } else {
 
212
        if (osflags & PR_TRUNCATE)
 
213
            flags = TRUNCATE_EXISTING;
 
214
        else
 
215
            flags = OPEN_EXISTING;
 
216
    }
 
217
 
 
218
    file = CreateFile(name,
 
219
                      access,
 
220
                      FILE_SHARE_READ|FILE_SHARE_WRITE,
 
221
                      NULL,
 
222
                      flags,
 
223
                      flag6,
 
224
                      NULL);
 
225
    if (file == INVALID_HANDLE_VALUE) {
 
226
                _PR_MD_MAP_OPEN_ERROR(GetLastError());
 
227
        return -1; 
 
228
        }
 
229
 
 
230
    return (PRInt32)file;
 
231
}
 
232
 
 
233
PRInt32
 
234
_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode)
 
235
{
 
236
    HANDLE file;
 
237
    PRInt32 access = 0;
 
238
    PRInt32 flags = 0;
 
239
    PRInt32 flag6 = 0;
 
240
    SECURITY_ATTRIBUTES sa;
 
241
    LPSECURITY_ATTRIBUTES lpSA = NULL;
 
242
    PSECURITY_DESCRIPTOR pSD = NULL;
 
243
    PACL pACL = NULL;
 
244
 
 
245
    if (osflags & PR_CREATE_FILE) {
 
246
        if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
 
247
                &pSD, &pACL) == PR_SUCCESS) {
 
248
            sa.nLength = sizeof(sa);
 
249
            sa.lpSecurityDescriptor = pSD;
 
250
            sa.bInheritHandle = FALSE;
 
251
            lpSA = &sa;
 
252
        }
 
253
    }
 
254
    
 
255
    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
 
256
 
 
257
    if (osflags & PR_RDONLY || osflags & PR_RDWR)
 
258
        access |= GENERIC_READ;
 
259
    if (osflags & PR_WRONLY || osflags & PR_RDWR)
 
260
        access |= GENERIC_WRITE;
 
261
 
 
262
    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
 
263
        flags = CREATE_NEW;
 
264
    else if (osflags & PR_CREATE_FILE) {
 
265
        if (osflags & PR_TRUNCATE)
 
266
            flags = CREATE_ALWAYS;
 
267
        else
 
268
            flags = OPEN_ALWAYS;
 
269
    } else {
 
270
        if (osflags & PR_TRUNCATE)
 
271
            flags = TRUNCATE_EXISTING;
 
272
        else
 
273
            flags = OPEN_EXISTING;
 
274
    }
 
275
 
 
276
    file = CreateFile(name,
 
277
                      access,
 
278
                      FILE_SHARE_READ|FILE_SHARE_WRITE,
 
279
                      lpSA,
 
280
                      flags,
 
281
                      flag6,
 
282
                      NULL);
 
283
    if (lpSA != NULL) {
 
284
        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
 
285
    }
 
286
    if (file == INVALID_HANDLE_VALUE) {
 
287
                _PR_MD_MAP_OPEN_ERROR(GetLastError());
 
288
        return -1; 
 
289
        }
 
290
 
 
291
    return (PRInt32)file;
 
292
}
 
293
 
 
294
PRInt32
 
295
_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
 
296
{
 
297
    PRUint32 bytes;
 
298
    int rv, err;
 
299
 
 
300
    rv = ReadFile((HANDLE)fd->secret->md.osfd,
 
301
            (LPVOID)buf,
 
302
            len,
 
303
            &bytes,
 
304
            NULL);
 
305
    
 
306
    if (rv == 0) 
 
307
    {
 
308
        err = GetLastError();
 
309
        /* ERROR_HANDLE_EOF can only be returned by async io */
 
310
        PR_ASSERT(err != ERROR_HANDLE_EOF);
 
311
        if (err == ERROR_BROKEN_PIPE)
 
312
            return 0;
 
313
                else {
 
314
                        _PR_MD_MAP_READ_ERROR(err);
 
315
        return -1;
 
316
    }
 
317
    }
 
318
    return bytes;
 
319
}
 
320
 
 
321
PRInt32
 
322
_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
 
323
{
 
324
    PRInt32 f = fd->secret->md.osfd;
 
325
    PRInt32 bytes;
 
326
    int rv;
 
327
    PRThread *me = _PR_MD_CURRENT_THREAD();
 
328
    
 
329
    rv = WriteFile((HANDLE)f,
 
330
            buf,
 
331
            len,
 
332
            &bytes,
 
333
            NULL );
 
334
            
 
335
    if (rv == 0) 
 
336
    {
 
337
                _PR_MD_MAP_WRITE_ERROR(GetLastError());
 
338
        return -1;
 
339
    }
 
340
    return bytes;
 
341
} /* --- end _PR_MD_WRITE() --- */
 
342
 
 
343
PROffset32
 
344
_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
 
345
{
 
346
    DWORD moveMethod;
 
347
    PROffset32 rv;
 
348
 
 
349
    switch (whence) {
 
350
        case PR_SEEK_SET:
 
351
            moveMethod = FILE_BEGIN;
 
352
            break;
 
353
        case PR_SEEK_CUR:
 
354
            moveMethod = FILE_CURRENT;
 
355
            break;
 
356
        case PR_SEEK_END:
 
357
            moveMethod = FILE_END;
 
358
            break;
 
359
        default:
 
360
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
361
            return -1;
 
362
    }
 
363
 
 
364
    rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod);
 
365
 
 
366
    /*
 
367
     * If the lpDistanceToMoveHigh argument (third argument) is
 
368
     * NULL, SetFilePointer returns 0xffffffff on failure.
 
369
     */
 
370
    if (-1 == rv) {
 
371
        _PR_MD_MAP_LSEEK_ERROR(GetLastError());
 
372
    }
 
373
    return rv;
 
374
}
 
375
 
 
376
PROffset64
 
377
_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
 
378
{
 
379
    DWORD moveMethod;
 
380
    LARGE_INTEGER li;
 
381
    DWORD err;
 
382
 
 
383
    switch (whence) {
 
384
        case PR_SEEK_SET:
 
385
            moveMethod = FILE_BEGIN;
 
386
            break;
 
387
        case PR_SEEK_CUR:
 
388
            moveMethod = FILE_CURRENT;
 
389
            break;
 
390
        case PR_SEEK_END:
 
391
            moveMethod = FILE_END;
 
392
            break;
 
393
        default:
 
394
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
395
            return -1;
 
396
    }
 
397
 
 
398
    li.QuadPart = offset;
 
399
    li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd,
 
400
            li.LowPart, &li.HighPart, moveMethod);
 
401
 
 
402
    if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) {
 
403
        _PR_MD_MAP_LSEEK_ERROR(err);
 
404
        li.QuadPart = -1;
 
405
    }
 
406
    return li.QuadPart;
 
407
}
 
408
 
 
409
/*
 
410
 * This is documented to succeed on read-only files, but Win32's
 
411
 * FlushFileBuffers functions fails with "access denied" in such a
 
412
 * case.  So we only signal an error if the error is *not* "access
 
413
 * denied".
 
414
 */
 
415
PRInt32
 
416
_PR_MD_FSYNC(PRFileDesc *fd)
 
417
{
 
418
    /*
 
419
     * From the documentation:
 
420
     *
 
421
     *     On Windows NT, the function FlushFileBuffers fails if hFile
 
422
     *     is a handle to console output. That is because console
 
423
     *     output is not buffered. The function returns FALSE, and
 
424
     *     GetLastError returns ERROR_INVALID_HANDLE.
 
425
     *
 
426
     * On the other hand, on Win95, it returns without error.  I cannot
 
427
     * assume that 0, 1, and 2 are console, because if someone closes
 
428
     * System.out and then opens a file, they might get file descriptor
 
429
     * 1.  An error on *that* version of 1 should be reported, whereas
 
430
     * an error on System.out (which was the original 1) should be
 
431
     * ignored.  So I use isatty() to ensure that such an error was due
 
432
     * to this bogosity, and if it was, I ignore the error.
 
433
     */
 
434
 
 
435
    BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
 
436
 
 
437
    if (!ok) {
 
438
        DWORD err = GetLastError();
 
439
        if (err != ERROR_ACCESS_DENIED) {       // from winerror.h
 
440
                        _PR_MD_MAP_FSYNC_ERROR(err);
 
441
            return -1;
 
442
        }
 
443
    }
 
444
    return 0;
 
445
}
 
446
 
 
447
PRInt32
 
448
_MD_CloseFile(PRInt32 osfd)
 
449
{
 
450
    PRInt32 rv;
 
451
    
 
452
    rv = (CloseHandle((HANDLE)osfd))?0:-1;
 
453
        if (rv == -1)
 
454
                _PR_MD_MAP_CLOSE_ERROR(GetLastError());
 
455
    return rv;
 
456
}
 
457
 
 
458
 
 
459
/* --- DIR IO ------------------------------------------------------------ */
 
460
#define GetFileFromDIR(d)       (d)->d_entry.cFileName
 
461
#define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
 
462
 
 
463
void FlipSlashes(char *cp, int len)
 
464
{
 
465
    while (--len >= 0) {
 
466
        if (cp[0] == '/') {
 
467
            cp[0] = PR_DIRECTORY_SEPARATOR;
 
468
        }
 
469
        cp = _mbsinc(cp);
 
470
    }
 
471
} /* end FlipSlashes() */
 
472
 
 
473
 
 
474
/*
 
475
**
 
476
** Local implementations of standard Unix RTL functions which are not provided
 
477
** by the VC RTL.
 
478
**
 
479
*/
 
480
 
 
481
PRStatus
 
482
_PR_MD_CLOSE_DIR(_MDDir *d)
 
483
{
 
484
    if ( d ) {
 
485
        if (FindClose(d->d_hdl)) {
 
486
        d->magic = (PRUint32)-1;
 
487
        return PR_SUCCESS;
 
488
                } else {
 
489
                        _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
 
490
                return PR_FAILURE;
 
491
                }
 
492
    }
 
493
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
494
    return PR_FAILURE;
 
495
}
 
496
 
 
497
 
 
498
PRStatus
 
499
_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
 
500
{
 
501
    char filename[ MAX_PATH ];
 
502
    int len;
 
503
 
 
504
    len = strlen(name);
 
505
    /* Need 5 bytes for \*.* and the trailing null byte. */
 
506
    if (len + 5 > MAX_PATH) {
 
507
        PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
 
508
        return PR_FAILURE;
 
509
    }
 
510
    strcpy(filename, name);
 
511
 
 
512
    /*
 
513
     * If 'name' ends in a slash or backslash, do not append
 
514
     * another backslash.
 
515
     */
 
516
    if (filename[len - 1] == '/' || filename[len - 1] == '\\') {
 
517
        len--;
 
518
    }
 
519
    strcpy(&filename[len], "\\*.*");
 
520
    FlipSlashes( filename, strlen(filename) );
 
521
 
 
522
    d->d_hdl = FindFirstFile( filename, &(d->d_entry) );
 
523
    if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
 
524
                _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
525
        return PR_FAILURE;
 
526
    }
 
527
    d->firstEntry = PR_TRUE;
 
528
    d->magic = _MD_MAGIC_DIR;
 
529
    return PR_SUCCESS;
 
530
}
 
531
 
 
532
char *
 
533
_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
 
534
{
 
535
    PRInt32 err;
 
536
    BOOL rv;
 
537
    char *fileName;
 
538
 
 
539
    if ( d ) {
 
540
        while (1) {
 
541
            if (d->firstEntry) {
 
542
                d->firstEntry = PR_FALSE;
 
543
                rv = 1;
 
544
            } else {
 
545
                rv = FindNextFile(d->d_hdl, &(d->d_entry));
 
546
            }
 
547
            if (rv == 0) {
 
548
                break;
 
549
            }
 
550
            fileName = GetFileFromDIR(d);
 
551
            if ( (flags & PR_SKIP_DOT) &&
 
552
                 (fileName[0] == '.') && (fileName[1] == '\0'))
 
553
                 continue;
 
554
            if ( (flags & PR_SKIP_DOT_DOT) &&
 
555
                 (fileName[0] == '.') && (fileName[1] == '.') &&
 
556
                 (fileName[2] == '\0'))
 
557
                 continue;
 
558
            if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
 
559
                 continue;
 
560
            return fileName;
 
561
        }
 
562
        err = GetLastError();
 
563
        PR_ASSERT(NO_ERROR != err);
 
564
                        _PR_MD_MAP_READDIR_ERROR(err);
 
565
        return NULL;
 
566
                }
 
567
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
568
    return NULL;
 
569
}
 
570
 
 
571
PRInt32
 
572
_PR_MD_DELETE(const char *name)
 
573
{
 
574
    if (DeleteFile(name)) {
 
575
        return 0;
 
576
    } else {
 
577
                _PR_MD_MAP_DELETE_ERROR(GetLastError());
 
578
        return -1;
 
579
    }
 
580
}
 
581
 
 
582
void
 
583
_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm)
 
584
{
 
585
    PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
 
586
    CopyMemory(prtm, filetime, sizeof(PRTime));
 
587
#if defined(__MINGW32__)
 
588
    *prtm = (*prtm - _pr_filetime_offset) / 10LL;
 
589
#else
 
590
    *prtm = (*prtm - _pr_filetime_offset) / 10i64;
 
591
#endif
 
592
 
 
593
#ifdef DEBUG
 
594
    /* Doublecheck our calculation. */
 
595
    {
 
596
        SYSTEMTIME systime;
 
597
        PRExplodedTime etm;
 
598
        PRTime cmp; /* for comparison */
 
599
        BOOL rv;
 
600
 
 
601
        rv = FileTimeToSystemTime(filetime, &systime);
 
602
        PR_ASSERT(0 != rv);
 
603
 
 
604
        /*
 
605
         * PR_ImplodeTime ignores wday and yday.
 
606
         */
 
607
        etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC;
 
608
        etm.tm_sec = systime.wSecond;
 
609
        etm.tm_min = systime.wMinute;
 
610
        etm.tm_hour = systime.wHour;
 
611
        etm.tm_mday = systime.wDay;
 
612
        etm.tm_month = systime.wMonth - 1;
 
613
        etm.tm_year = systime.wYear;
 
614
        /*
 
615
         * It is not well-documented what time zone the FILETIME's
 
616
         * are in.  WIN32_FIND_DATA is documented to be in UTC (GMT).
 
617
         * But BY_HANDLE_FILE_INFORMATION is unclear about this.
 
618
         * By our best judgement, we assume that FILETIME is in UTC.
 
619
         */
 
620
        etm.tm_params.tp_gmt_offset = 0;
 
621
        etm.tm_params.tp_dst_offset = 0;
 
622
        cmp = PR_ImplodeTime(&etm);
 
623
 
 
624
        /*
 
625
         * SYSTEMTIME is in milliseconds precision, so we convert PRTime's
 
626
         * microseconds to milliseconds before doing the comparison.
 
627
         */
 
628
        PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC));
 
629
    }
 
630
#endif /* DEBUG */
 
631
}
 
632
 
 
633
PRInt32
 
634
_PR_MD_STAT(const char *fn, struct stat *info)
 
635
{
 
636
    PRInt32 rv;
 
637
 
 
638
    rv = _stat(fn, (struct _stat *)info);
 
639
    if (-1 == rv) {
 
640
        /*
 
641
         * Check for MSVC runtime library _stat() bug.
 
642
         * (It's really a bug in FindFirstFile().)
 
643
         * If a pathname ends in a backslash or slash,
 
644
         * e.g., c:\temp\ or c:/temp/, _stat() will fail.
 
645
         * Note: a pathname ending in a slash (e.g., c:/temp/)
 
646
         * can be handled by _stat() on NT but not on Win95.
 
647
         *
 
648
         * We remove the backslash or slash at the end and
 
649
         * try again.
 
650
         */
 
651
 
 
652
        int len = strlen(fn);
 
653
        if (len > 0 && len <= _MAX_PATH
 
654
                && (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
 
655
            char newfn[_MAX_PATH + 1];
 
656
 
 
657
            strcpy(newfn, fn);
 
658
            newfn[len - 1] = '\0';
 
659
            rv = _stat(newfn, (struct _stat *)info);
 
660
        }
 
661
    }
 
662
 
 
663
    if (-1 == rv) {
 
664
        _PR_MD_MAP_STAT_ERROR(errno);
 
665
    }
 
666
    return rv;
 
667
}
 
668
 
 
669
#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
 
670
 
 
671
/*
 
672
 * IsRootDirectory --
 
673
 *
 
674
 * Return PR_TRUE if the pathname 'fn' is a valid root directory,
 
675
 * else return PR_FALSE.  The char buffer pointed to by 'fn' must
 
676
 * be writable.  During the execution of this function, the contents
 
677
 * of the buffer pointed to by 'fn' may be modified, but on return
 
678
 * the original contents will be restored.  'buflen' is the size of
 
679
 * the buffer pointed to by 'fn'.
 
680
 *
 
681
 * Root directories come in three formats:
 
682
 * 1. / or \, meaning the root directory of the current drive.
 
683
 * 2. C:/ or C:\, where C is a drive letter.
 
684
 * 3. \\<server name>\<share point name>\ or
 
685
 *    \\<server name>\<share point name>, meaning the root directory
 
686
 *    of a UNC (Universal Naming Convention) name.
 
687
 */
 
688
 
 
689
static PRBool
 
690
IsRootDirectory(char *fn, size_t buflen)
 
691
{
 
692
    char *p;
 
693
    PRBool slashAdded = PR_FALSE;
 
694
    PRBool rv = PR_FALSE;
 
695
 
 
696
    if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') {
 
697
        return PR_TRUE;
 
698
    }
 
699
 
 
700
    if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2])
 
701
            && fn[3] == '\0') {
 
702
        rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
 
703
        return rv;
 
704
    }
 
705
 
 
706
    /* The UNC root directory */
 
707
 
 
708
    if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) {
 
709
        /* The 'server' part should have at least one character. */
 
710
        p = &fn[2];
 
711
        if (*p == '\0' || _PR_IS_SLASH(*p)) {
 
712
            return PR_FALSE;
 
713
        }
 
714
 
 
715
        /* look for the next slash */
 
716
        do {
 
717
            p++;
 
718
        } while (*p != '\0' && !_PR_IS_SLASH(*p));
 
719
        if (*p == '\0') {
 
720
            return PR_FALSE;
 
721
        }
 
722
 
 
723
        /* The 'share' part should have at least one character. */
 
724
        p++;
 
725
        if (*p == '\0' || _PR_IS_SLASH(*p)) {
 
726
            return PR_FALSE;
 
727
        }
 
728
 
 
729
        /* look for the final slash */
 
730
        do {
 
731
            p++;
 
732
        } while (*p != '\0' && !_PR_IS_SLASH(*p));
 
733
        if (_PR_IS_SLASH(*p) && p[1] != '\0') {
 
734
            return PR_FALSE;
 
735
        }
 
736
        if (*p == '\0') {
 
737
            /*
 
738
             * GetDriveType() doesn't work correctly if the
 
739
             * path is of the form \\server\share, so we add
 
740
             * a final slash temporarily.
 
741
             */
 
742
            if ((p + 1) < (fn + buflen)) {
 
743
                *p++ = '\\';
 
744
                *p = '\0';
 
745
                slashAdded = PR_TRUE;
 
746
            } else {
 
747
                return PR_FALSE; /* name too long */
 
748
            }
 
749
        }
 
750
        rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
 
751
        /* restore the 'fn' buffer */
 
752
        if (slashAdded) {
 
753
            *--p = '\0';
 
754
        }
 
755
    }
 
756
    return rv;
 
757
}
 
758
 
 
759
PRInt32
 
760
_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
 
761
{
 
762
    HANDLE hFindFile;
 
763
    WIN32_FIND_DATA findFileData;
 
764
    char pathbuf[MAX_PATH + 1];
 
765
    
 
766
    if (NULL == fn || '\0' == *fn) {
 
767
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
768
        return -1;
 
769
    }
 
770
 
 
771
    /*
 
772
     * FindFirstFile() expands wildcard characters.  So
 
773
     * we make sure the pathname contains no wildcard.
 
774
     */
 
775
    if (NULL != _mbspbrk(fn, "?*")) {
 
776
        PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
 
777
        return -1;
 
778
    }
 
779
 
 
780
    hFindFile = FindFirstFile(fn, &findFileData);
 
781
    if (INVALID_HANDLE_VALUE == hFindFile) {
 
782
        DWORD len;
 
783
        char *filePart;
 
784
 
 
785
        /*
 
786
         * FindFirstFile() does not work correctly on root directories.
 
787
         * It also doesn't work correctly on a pathname that ends in a
 
788
         * slash.  So we first check to see if the pathname specifies a
 
789
         * root directory.  If not, and if the pathname ends in a slash,
 
790
         * we remove the final slash and try again.
 
791
         */
 
792
 
 
793
        /*
 
794
         * If the pathname does not contain ., \, and /, it cannot be
 
795
         * a root directory or a pathname that ends in a slash.
 
796
         */
 
797
        if (NULL == _mbspbrk(fn, ".\\/")) {
 
798
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
799
            return -1;
 
800
        } 
 
801
        len = GetFullPathName(fn, sizeof(pathbuf), pathbuf,
 
802
                &filePart);
 
803
        if (0 == len) {
 
804
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
805
            return -1;
 
806
        }
 
807
        if (len > sizeof(pathbuf)) {
 
808
            PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
 
809
            return -1;
 
810
        }
 
811
        if (IsRootDirectory(pathbuf, sizeof(pathbuf))) {
 
812
            info->type = PR_FILE_DIRECTORY;
 
813
            info->size = 0;
 
814
            /*
 
815
             * These timestamps don't make sense for root directories.
 
816
             */
 
817
            info->modifyTime = 0;
 
818
            info->creationTime = 0;
 
819
            return 0;
 
820
        }
 
821
        if (!_PR_IS_SLASH(pathbuf[len - 1])) {
 
822
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
823
            return -1;
 
824
        } else {
 
825
            pathbuf[len - 1] = '\0';
 
826
            hFindFile = FindFirstFile(pathbuf, &findFileData);
 
827
            if (INVALID_HANDLE_VALUE == hFindFile) {
 
828
                _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
829
                return -1;
 
830
            }
 
831
        }
 
832
    }
 
833
 
 
834
    FindClose(hFindFile);
 
835
 
 
836
    if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
 
837
        info->type = PR_FILE_DIRECTORY;
 
838
    } else {
 
839
        info->type = PR_FILE_FILE;
 
840
    }
 
841
 
 
842
    info->size = findFileData.nFileSizeHigh;
 
843
    info->size = (info->size << 32) + findFileData.nFileSizeLow;
 
844
 
 
845
    _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
 
846
 
 
847
    if (0 == findFileData.ftCreationTime.dwLowDateTime &&
 
848
            0 == findFileData.ftCreationTime.dwHighDateTime) {
 
849
        info->creationTime = info->modifyTime;
 
850
    } else {
 
851
        _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
 
852
                &info->creationTime);
 
853
    }
 
854
 
 
855
    return 0;
 
856
}
 
857
 
 
858
PRInt32
 
859
_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
 
860
{
 
861
    PRFileInfo64 info64;
 
862
    PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64);
 
863
    if (0 == rv)
 
864
    {
 
865
        info->type = info64.type;
 
866
        info->size = (PRUint32) info64.size;
 
867
        info->modifyTime = info64.modifyTime;
 
868
        info->creationTime = info64.creationTime;
 
869
    }
 
870
    return rv;
 
871
}
 
872
 
 
873
PRInt32
 
874
_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
 
875
{
 
876
    int rv;
 
877
 
 
878
    BY_HANDLE_FILE_INFORMATION hinfo;
 
879
 
 
880
    rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo);
 
881
    if (rv == FALSE) {
 
882
                _PR_MD_MAP_FSTAT_ERROR(GetLastError());
 
883
        return -1;
 
884
        }
 
885
 
 
886
    if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 
887
        info->type = PR_FILE_DIRECTORY;
 
888
    else
 
889
        info->type = PR_FILE_FILE;
 
890
 
 
891
    info->size = hinfo.nFileSizeHigh;
 
892
    info->size = (info->size << 32) + hinfo.nFileSizeLow;
 
893
 
 
894
    _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) );
 
895
    _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) );
 
896
 
 
897
    return 0;
 
898
}
 
899
 
 
900
PRInt32
 
901
_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
 
902
{
 
903
    PRFileInfo64 info64;
 
904
    int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64);
 
905
    if (0 == rv)
 
906
    {
 
907
        info->type = info64.type;
 
908
        info->modifyTime = info64.modifyTime;
 
909
        info->creationTime = info64.creationTime;
 
910
        LL_L2I(info->size, info64.size);
 
911
    }
 
912
    return rv;
 
913
}
 
914
 
 
915
PRStatus
 
916
_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
 
917
{
 
918
    BOOL rv;
 
919
 
 
920
    /*
 
921
     * The SetHandleInformation function fails with the
 
922
     * ERROR_CALL_NOT_IMPLEMENTED error on Win95.
 
923
     */
 
924
    rv = SetHandleInformation(
 
925
            (HANDLE)fd->secret->md.osfd,
 
926
            HANDLE_FLAG_INHERIT,
 
927
            inheritable ? HANDLE_FLAG_INHERIT : 0);
 
928
    if (0 == rv) {
 
929
        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
 
930
        return PR_FAILURE;
 
931
    }
 
932
    return PR_SUCCESS;
 
933
 
934
 
 
935
void
 
936
_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported)
 
937
{
 
938
    if (imported) {
 
939
        fd->secret->inheritable = _PR_TRI_UNKNOWN;
 
940
    } else {
 
941
        fd->secret->inheritable = _PR_TRI_FALSE;
 
942
    }
 
943
}
 
944
 
 
945
void
 
946
_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd)
 
947
{
 
948
    DWORD flags;
 
949
 
 
950
    PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
 
951
    if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) {
 
952
        if (flags & HANDLE_FLAG_INHERIT) {
 
953
            fd->secret->inheritable = _PR_TRI_TRUE;
 
954
        } else {
 
955
            fd->secret->inheritable = _PR_TRI_FALSE;
 
956
        }
 
957
    }
 
958
}
 
959
 
 
960
PRInt32
 
961
_PR_MD_RENAME(const char *from, const char *to)
 
962
{
 
963
    /* Does this work with dot-relative pathnames? */
 
964
    if (MoveFile(from, to)) {
 
965
        return 0;
 
966
    } else {
 
967
                _PR_MD_MAP_RENAME_ERROR(GetLastError());
 
968
        return -1;
 
969
    }
 
970
}
 
971
 
 
972
PRInt32
 
973
_PR_MD_ACCESS(const char *name, PRAccessHow how)
 
974
{
 
975
PRInt32 rv;
 
976
    switch (how) {
 
977
      case PR_ACCESS_WRITE_OK:
 
978
        rv = _access(name, 02);
 
979
                break;
 
980
      case PR_ACCESS_READ_OK:
 
981
        rv = _access(name, 04);
 
982
                break;
 
983
      case PR_ACCESS_EXISTS:
 
984
        return _access(name, 00);
 
985
                break;
 
986
      default:
 
987
                PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
988
                return -1;
 
989
    }
 
990
        if (rv < 0)
 
991
                _PR_MD_MAP_ACCESS_ERROR(errno);
 
992
    return rv;
 
993
}
 
994
 
 
995
PRInt32
 
996
_PR_MD_MKDIR(const char *name, PRIntn mode)
 
997
{
 
998
    /* XXXMB - how to translate the "mode"??? */
 
999
    if (CreateDirectory(name, NULL)) {
 
1000
        return 0;
 
1001
    } else {
 
1002
                _PR_MD_MAP_MKDIR_ERROR(GetLastError());
 
1003
        return -1;
 
1004
    }
 
1005
}
 
1006
 
 
1007
PRInt32
 
1008
_PR_MD_MAKE_DIR(const char *name, PRIntn mode)
 
1009
{
 
1010
    BOOL rv;
 
1011
    SECURITY_ATTRIBUTES sa;
 
1012
    LPSECURITY_ATTRIBUTES lpSA = NULL;
 
1013
    PSECURITY_DESCRIPTOR pSD = NULL;
 
1014
    PACL pACL = NULL;
 
1015
 
 
1016
    if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable,
 
1017
            &pSD, &pACL) == PR_SUCCESS) {
 
1018
        sa.nLength = sizeof(sa);
 
1019
        sa.lpSecurityDescriptor = pSD;
 
1020
        sa.bInheritHandle = FALSE;
 
1021
        lpSA = &sa;
 
1022
    }
 
1023
    rv = CreateDirectory(name, lpSA);
 
1024
    if (lpSA != NULL) {
 
1025
        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
 
1026
    }
 
1027
    if (rv) {
 
1028
        return 0;
 
1029
    } else {
 
1030
        _PR_MD_MAP_MKDIR_ERROR(GetLastError());
 
1031
        return -1;
 
1032
    }
 
1033
}
 
1034
 
 
1035
PRInt32
 
1036
_PR_MD_RMDIR(const char *name)
 
1037
{
 
1038
    if (RemoveDirectory(name)) {
 
1039
        return 0;
 
1040
    } else {
 
1041
                _PR_MD_MAP_RMDIR_ERROR(GetLastError());
 
1042
        return -1;
 
1043
    }
 
1044
}
 
1045
 
 
1046
PRStatus
 
1047
_PR_MD_LOCKFILE(PRInt32 f)
 
1048
{
 
1049
    PRStatus  rc = PR_SUCCESS;
 
1050
        DWORD     rv;
 
1051
 
 
1052
        rv = LockFile( (HANDLE)f,
 
1053
                0l, 0l,
 
1054
                0x0l, 0xffffffffl ); 
 
1055
        if ( rv == 0 ) {
 
1056
        DWORD rc = GetLastError();
 
1057
        PR_LOG( _pr_io_lm, PR_LOG_ERROR,
 
1058
            ("_PR_MD_LOCKFILE() failed. Error: %d", rc ));
 
1059
        rc = PR_FAILURE;
 
1060
    }
 
1061
 
 
1062
    return rc;
 
1063
} /* end _PR_MD_LOCKFILE() */
 
1064
 
 
1065
PRStatus
 
1066
_PR_MD_TLOCKFILE(PRInt32 f)
 
1067
{
 
1068
    PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
 
1069
    return PR_FAILURE;
 
1070
} /* end _PR_MD_TLOCKFILE() */
 
1071
 
 
1072
 
 
1073
PRStatus
 
1074
_PR_MD_UNLOCKFILE(PRInt32 f)
 
1075
{
 
1076
        PRInt32   rv;
 
1077
    
 
1078
    rv = UnlockFile( (HANDLE) f,
 
1079
                0l, 0l,
 
1080
            0x0l, 0xffffffffl ); 
 
1081
            
 
1082
    if ( rv )
 
1083
    {
 
1084
        return PR_SUCCESS;
 
1085
    }
 
1086
    else
 
1087
    {
 
1088
                _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
 
1089
                return PR_FAILURE;
 
1090
    }
 
1091
} /* end _PR_MD_UNLOCKFILE() */
 
1092
 
 
1093
PRInt32
 
1094
_PR_MD_PIPEAVAILABLE(PRFileDesc *fd)
 
1095
{
 
1096
    if (NULL == fd)
 
1097
                PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
 
1098
        else
 
1099
                PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
1100
    return -1;
 
1101
}
 
1102
 
 
1103
#ifdef MOZ_UNICODE
 
1104
 
 
1105
typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
 
1106
static CreateFileWFn createFileW = NULL; 
 
1107
typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW);
 
1108
static FindFirstFileWFn findFirstFileW = NULL; 
 
1109
typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW);
 
1110
static FindNextFileWFn findNextFileW = NULL; 
 
1111
typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *);
 
1112
static GetFullPathNameWFn getFullPathNameW = NULL; 
 
1113
typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR);
 
1114
static GetDriveTypeWFn getDriveTypeW = NULL; 
 
1115
 
 
1116
static void InitUnicodeSupport(void)
 
1117
{
 
1118
    HMODULE module;
 
1119
 
 
1120
    /*
 
1121
     * The W functions do not exist on Win9x.  NSPR won't run on Win9x
 
1122
     * if we call the W functions directly.  Use GetProcAddress() to
 
1123
     * look up their addresses at run time.
 
1124
     */
 
1125
 
 
1126
    module = GetModuleHandle("Kernel32.dll");
 
1127
    if (!module) {
 
1128
        return;
 
1129
    }
 
1130
 
 
1131
    createFileW = (CreateFileWFn)GetProcAddress(module, "CreateFileW"); 
 
1132
    findFirstFileW = (FindFirstFileWFn)GetProcAddress(module, "FindFirstFileW"); 
 
1133
    findNextFileW = (FindNextFileWFn)GetProcAddress(module, "FindNextFileW"); 
 
1134
    getDriveTypeW = (GetDriveTypeWFn)GetProcAddress(module, "GetDriveTypeW"); 
 
1135
    getFullPathNameW = (GetFullPathNameWFn)GetProcAddress(module, "GetFullPathNameW"); 
 
1136
}
 
1137
 
 
1138
/* ================ UTF16 Interfaces ================================ */
 
1139
void FlipSlashesW(PRUnichar *cp, int len)
 
1140
{
 
1141
    while (--len >= 0) {
 
1142
        if (cp[0] == L'/') {
 
1143
            cp[0] = L'\\';
 
1144
        }
 
1145
        cp++;
 
1146
    }
 
1147
} /* end FlipSlashesW() */
 
1148
 
 
1149
PRInt32
 
1150
_PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode)
 
1151
{
 
1152
    HANDLE file;
 
1153
    PRInt32 access = 0;
 
1154
    PRInt32 flags = 0;
 
1155
    PRInt32 flag6 = 0;
 
1156
    SECURITY_ATTRIBUTES sa;
 
1157
    LPSECURITY_ATTRIBUTES lpSA = NULL;
 
1158
    PSECURITY_DESCRIPTOR pSD = NULL;
 
1159
    PACL pACL = NULL;
 
1160
 
 
1161
    if (!createFileW) {
 
1162
        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
1163
        return -1;
 
1164
    }
 
1165
 
 
1166
    if (osflags & PR_CREATE_FILE) {
 
1167
        if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
 
1168
                &pSD, &pACL) == PR_SUCCESS) {
 
1169
            sa.nLength = sizeof(sa);
 
1170
            sa.lpSecurityDescriptor = pSD;
 
1171
            sa.bInheritHandle = FALSE;
 
1172
            lpSA = &sa;
 
1173
        }
 
1174
    }
 
1175
 
 
1176
    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
 
1177
 
 
1178
    if (osflags & PR_RDONLY || osflags & PR_RDWR)
 
1179
        access |= GENERIC_READ;
 
1180
    if (osflags & PR_WRONLY || osflags & PR_RDWR)
 
1181
        access |= GENERIC_WRITE;
 
1182
 
 
1183
    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
 
1184
        flags = CREATE_NEW;
 
1185
    else if (osflags & PR_CREATE_FILE) {
 
1186
        if (osflags & PR_TRUNCATE)
 
1187
            flags = CREATE_ALWAYS;
 
1188
        else
 
1189
            flags = OPEN_ALWAYS;
 
1190
    } else {
 
1191
        if (osflags & PR_TRUNCATE)
 
1192
            flags = TRUNCATE_EXISTING;
 
1193
        else
 
1194
            flags = OPEN_EXISTING;
 
1195
    }
 
1196
 
 
1197
    file = createFileW(name,
 
1198
                       access,
 
1199
                       FILE_SHARE_READ|FILE_SHARE_WRITE,
 
1200
                       lpSA,
 
1201
                       flags,
 
1202
                       flag6,
 
1203
                       NULL);
 
1204
    if (lpSA != NULL) {
 
1205
        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
 
1206
    }
 
1207
    if (file == INVALID_HANDLE_VALUE) {
 
1208
        _PR_MD_MAP_OPEN_ERROR(GetLastError());
 
1209
        return -1;
 
1210
    }
 
1211
 
 
1212
    return (PRInt32)file;
 
1213
}
 
1214
 
 
1215
PRStatus
 
1216
_PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name)
 
1217
{
 
1218
    PRUnichar filename[ MAX_PATH ];
 
1219
    int len;
 
1220
 
 
1221
    if (!findFirstFileW) {
 
1222
        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
1223
        return PR_FAILURE;
 
1224
    }
 
1225
 
 
1226
    len = wcslen(name);
 
1227
    /* Need 5 bytes for \*.* and the trailing null byte. */
 
1228
    if (len + 5 > MAX_PATH) {
 
1229
        PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
 
1230
        return PR_FAILURE;
 
1231
    }
 
1232
    wcscpy(filename, name);
 
1233
 
 
1234
    /*
 
1235
     * If 'name' ends in a slash or backslash, do not append
 
1236
     * another backslash.
 
1237
     */
 
1238
    if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') {
 
1239
        len--;
 
1240
    }
 
1241
    wcscpy(&filename[len], L"\\*.*");
 
1242
    FlipSlashesW( filename, wcslen(filename) );
 
1243
 
 
1244
    d->d_hdl = findFirstFileW( filename, &(d->d_entry) );
 
1245
    if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
 
1246
        _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
1247
        return PR_FAILURE;
 
1248
    }
 
1249
    d->firstEntry = PR_TRUE;
 
1250
    d->magic = _MD_MAGIC_DIR;
 
1251
    return PR_SUCCESS;
 
1252
}
 
1253
 
 
1254
PRUnichar *
 
1255
_PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags)
 
1256
{
 
1257
    PRInt32 err;
 
1258
    BOOL rv;
 
1259
    PRUnichar *fileName;
 
1260
 
 
1261
    if (!findNextFileW) {
 
1262
        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
1263
        return NULL;
 
1264
    }
 
1265
 
 
1266
    if ( d ) {
 
1267
        while (1) {
 
1268
            if (d->firstEntry) {
 
1269
                d->firstEntry = PR_FALSE;
 
1270
                rv = 1;
 
1271
            } else {
 
1272
                rv = findNextFileW(d->d_hdl, &(d->d_entry));
 
1273
            }
 
1274
            if (rv == 0) {
 
1275
                break;
 
1276
            }
 
1277
            fileName = GetFileFromDIR(d);
 
1278
            if ( (flags & PR_SKIP_DOT) &&
 
1279
                 (fileName[0] == L'.') && (fileName[1] == L'\0'))
 
1280
                continue;
 
1281
            if ( (flags & PR_SKIP_DOT_DOT) &&
 
1282
                 (fileName[0] == L'.') && (fileName[1] == L'.') &&
 
1283
                 (fileName[2] == L'\0'))
 
1284
                continue;
 
1285
            if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
 
1286
                continue;
 
1287
            return fileName;
 
1288
        }
 
1289
        err = GetLastError();
 
1290
        PR_ASSERT(NO_ERROR != err);
 
1291
        _PR_MD_MAP_READDIR_ERROR(err);
 
1292
        return NULL;
 
1293
    }
 
1294
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
1295
    return NULL;
 
1296
}
 
1297
 
 
1298
PRStatus
 
1299
_PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d)
 
1300
{
 
1301
    if ( d ) {
 
1302
        if (FindClose(d->d_hdl)) {
 
1303
            d->magic = (PRUint32)-1;
 
1304
            return PR_SUCCESS;
 
1305
        } else {
 
1306
            _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
 
1307
            return PR_FAILURE;
 
1308
        }
 
1309
    }
 
1310
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
1311
    return PR_FAILURE;
 
1312
}
 
1313
 
 
1314
#define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\')
 
1315
 
 
1316
/*
 
1317
 * IsRootDirectoryW --
 
1318
 *
 
1319
 * Return PR_TRUE if the pathname 'fn' is a valid root directory,
 
1320
 * else return PR_FALSE.  The PRUnichar buffer pointed to by 'fn' must
 
1321
 * be writable.  During the execution of this function, the contents
 
1322
 * of the buffer pointed to by 'fn' may be modified, but on return
 
1323
 * the original contents will be restored.  'buflen' is the size of
 
1324
 * the buffer pointed to by 'fn', in PRUnichars.
 
1325
 *
 
1326
 * Root directories come in three formats:
 
1327
 * 1. / or \, meaning the root directory of the current drive.
 
1328
 * 2. C:/ or C:\, where C is a drive letter.
 
1329
 * 3. \\<server name>\<share point name>\ or
 
1330
 *    \\<server name>\<share point name>, meaning the root directory
 
1331
 *    of a UNC (Universal Naming Convention) name.
 
1332
 */
 
1333
 
 
1334
static PRBool
 
1335
IsRootDirectoryW(PRUnichar *fn, size_t buflen)
 
1336
{
 
1337
    PRUnichar *p;
 
1338
    PRBool slashAdded = PR_FALSE;
 
1339
    PRBool rv = PR_FALSE;
 
1340
 
 
1341
    if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') {
 
1342
        return PR_TRUE;
 
1343
    }
 
1344
 
 
1345
    if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2])
 
1346
            && fn[3] == L'\0') {
 
1347
        rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
 
1348
        return rv;
 
1349
    }
 
1350
 
 
1351
    /* The UNC root directory */
 
1352
 
 
1353
    if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) {
 
1354
        /* The 'server' part should have at least one character. */
 
1355
        p = &fn[2];
 
1356
        if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
 
1357
            return PR_FALSE;
 
1358
        }
 
1359
 
 
1360
        /* look for the next slash */
 
1361
        do {
 
1362
            p++;
 
1363
        } while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
 
1364
        if (*p == L'\0') {
 
1365
            return PR_FALSE;
 
1366
        }
 
1367
 
 
1368
        /* The 'share' part should have at least one character. */
 
1369
        p++;
 
1370
        if (*p == L'\0' || _PR_IS_W_SLASH(*p)) {
 
1371
            return PR_FALSE;
 
1372
        }
 
1373
 
 
1374
        /* look for the final slash */
 
1375
        do {
 
1376
            p++;
 
1377
        } while (*p != L'\0' && !_PR_IS_W_SLASH(*p));
 
1378
        if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') {
 
1379
            return PR_FALSE;
 
1380
        }
 
1381
        if (*p == L'\0') {
 
1382
            /*
 
1383
             * GetDriveType() doesn't work correctly if the
 
1384
             * path is of the form \\server\share, so we add
 
1385
             * a final slash temporarily.
 
1386
             */
 
1387
            if ((p + 1) < (fn + buflen)) {
 
1388
                *p++ = L'\\';
 
1389
                *p = L'\0';
 
1390
                slashAdded = PR_TRUE;
 
1391
            } else {
 
1392
                return PR_FALSE; /* name too long */
 
1393
            }
 
1394
        }
 
1395
        rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE;
 
1396
        /* restore the 'fn' buffer */
 
1397
        if (slashAdded) {
 
1398
            *--p = L'\0';
 
1399
        }
 
1400
    }
 
1401
    return rv;
 
1402
}
 
1403
 
 
1404
PRInt32
 
1405
_PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info)
 
1406
{
 
1407
    HANDLE hFindFile;
 
1408
    WIN32_FIND_DATAW findFileData;
 
1409
    PRUnichar pathbuf[MAX_PATH + 1];
 
1410
 
 
1411
    if (!findFirstFileW || !getFullPathNameW || !getDriveTypeW) {
 
1412
        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
1413
        return -1;
 
1414
    }
 
1415
    
 
1416
    if (NULL == fn || L'\0' == *fn) {
 
1417
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
1418
        return -1;
 
1419
    }
 
1420
 
 
1421
    /*
 
1422
     * FindFirstFile() expands wildcard characters.  So
 
1423
     * we make sure the pathname contains no wildcard.
 
1424
     */
 
1425
    if (NULL != wcspbrk(fn, L"?*")) {
 
1426
        PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
 
1427
        return -1;
 
1428
    }
 
1429
 
 
1430
    hFindFile = findFirstFileW(fn, &findFileData);
 
1431
    if (INVALID_HANDLE_VALUE == hFindFile) {
 
1432
        DWORD len;
 
1433
        PRUnichar *filePart;
 
1434
 
 
1435
        /*
 
1436
         * FindFirstFile() does not work correctly on root directories.
 
1437
         * It also doesn't work correctly on a pathname that ends in a
 
1438
         * slash.  So we first check to see if the pathname specifies a
 
1439
         * root directory.  If not, and if the pathname ends in a slash,
 
1440
         * we remove the final slash and try again.
 
1441
         */
 
1442
 
 
1443
        /*
 
1444
         * If the pathname does not contain ., \, and /, it cannot be
 
1445
         * a root directory or a pathname that ends in a slash.
 
1446
         */
 
1447
        if (NULL == wcspbrk(fn, L".\\/")) {
 
1448
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
1449
            return -1;
 
1450
        } 
 
1451
        len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf,
 
1452
                &filePart);
 
1453
        if (0 == len) {
 
1454
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
1455
            return -1;
 
1456
        }
 
1457
        if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) {
 
1458
            PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
 
1459
            return -1;
 
1460
        }
 
1461
        if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) {
 
1462
            info->type = PR_FILE_DIRECTORY;
 
1463
            info->size = 0;
 
1464
            /*
 
1465
             * These timestamps don't make sense for root directories.
 
1466
             */
 
1467
            info->modifyTime = 0;
 
1468
            info->creationTime = 0;
 
1469
            return 0;
 
1470
        }
 
1471
        if (!_PR_IS_W_SLASH(pathbuf[len - 1])) {
 
1472
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
1473
            return -1;
 
1474
        } else {
 
1475
            pathbuf[len - 1] = L'\0';
 
1476
            hFindFile = findFirstFileW(pathbuf, &findFileData);
 
1477
            if (INVALID_HANDLE_VALUE == hFindFile) {
 
1478
                _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
 
1479
                return -1;
 
1480
            }
 
1481
        }
 
1482
    }
 
1483
 
 
1484
    FindClose(hFindFile);
 
1485
 
 
1486
    if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
 
1487
        info->type = PR_FILE_DIRECTORY;
 
1488
    } else {
 
1489
        info->type = PR_FILE_FILE;
 
1490
    }
 
1491
 
 
1492
    info->size = findFileData.nFileSizeHigh;
 
1493
    info->size = (info->size << 32) + findFileData.nFileSizeLow;
 
1494
 
 
1495
    _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);
 
1496
 
 
1497
    if (0 == findFileData.ftCreationTime.dwLowDateTime &&
 
1498
            0 == findFileData.ftCreationTime.dwHighDateTime) {
 
1499
        info->creationTime = info->modifyTime;
 
1500
    } else {
 
1501
        _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
 
1502
                &info->creationTime);
 
1503
    }
 
1504
 
 
1505
    return 0;
 
1506
}
 
1507
/* ================ end of UTF16 Interfaces ================================ */
 
1508
#endif /* MOZ_UNICODE */