~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to erts/emulator/drivers/win32/win_efile.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * %CopyrightBegin%
3
 
 * 
4
 
 * Copyright Ericsson AB 1997-2009. All Rights Reserved.
5
 
 * 
 
3
 *
 
4
 * Copyright Ericsson AB 1997-2011. All Rights Reserved.
 
5
 *
6
6
 * The contents of this file are subject to the Erlang Public License,
7
7
 * Version 1.1, (the "License"); you may not use this file except in
8
8
 * compliance with the License. You should have received a copy of the
9
9
 * Erlang Public License along with this software. If not, it can be
10
10
 * retrieved online at http://www.erlang.org/.
11
 
 * 
 
11
 *
12
12
 * Software distributed under the License is distributed on an "AS IS"
13
13
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
 * the License for the specific language governing rights and limitations
15
15
 * under the License.
16
 
 * 
 
16
 *
17
17
 * %CopyrightEnd%
18
18
 */
19
19
/*
23
23
#include <windows.h>
24
24
#include "sys.h"
25
25
#include <ctype.h>
26
 
 
 
26
#include <wchar.h>
27
27
#include "erl_efile.h"
28
28
 
29
29
/*
30
30
 * Microsoft-specific function to map a WIN32 error code to a Posix errno.
31
31
 */
32
32
 
33
 
#define ISSLASH(a)  ((a) == '\\' || (a) == '/')
 
33
#define ISSLASH(a)  ((a) == L'\\' || (a) == L'/')
34
34
 
35
35
#define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR)
36
36
#define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG)
37
37
 
38
38
#define IS_DOT_OR_DOTDOT(s) \
39
 
    (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')))
 
39
    ((s)[0] == L'.' && ((s)[1] == L'\0' || ((s)[1] == L'.' && (s)[2] == L'\0')))
40
40
 
41
41
#ifndef INVALID_FILE_ATTRIBUTES
42
42
#define INVALID_FILE_ATTRIBUTES ((DWORD) 0xFFFFFFFF)
44
44
 
45
45
static int check_error(int result, Efile_error* errInfo);
46
46
static int set_error(Efile_error* errInfo);
47
 
static int IsRootUNCName(const char* path);
48
 
static int extract_root(char* name);
49
 
static unsigned short dos_to_posix_mode(int attr, const char *name);
 
47
static int is_root_unc_name(const WCHAR *path);
 
48
static int extract_root(WCHAR *name);
 
49
static unsigned short dos_to_posix_mode(int attr, const WCHAR *name);
50
50
 
51
51
static int errno_map(DWORD last_error) {
52
52
 
196
196
 
197
197
 
198
198
int
199
 
efile_mkdir(errInfo, name)
200
 
Efile_error* errInfo;           /* Where to return error codes. */
201
 
char* name;                     /* Name of directory to create. */
 
199
efile_mkdir(Efile_error* errInfo,       /* Where to return error codes. */
 
200
            char* name)                 /* Name of directory to create. */
202
201
{
203
 
    return check_error(mkdir(name), errInfo);
 
202
    return check_error(_wmkdir((WCHAR *) name), errInfo);
204
203
}
205
204
 
206
205
int
207
 
efile_rmdir(errInfo, name)
208
 
Efile_error* errInfo;           /* Where to return error codes. */
209
 
char* name;                     /* Name of directory to delete. */
 
206
efile_rmdir(Efile_error* errInfo,       /* Where to return error codes. */
 
207
            char* name)                 /* Name of directory to delete. */
210
208
{
211
209
    OSVERSIONINFO os;
212
210
    DWORD attr;
 
211
    WCHAR *wname = (WCHAR *) name;
213
212
 
214
 
    if (RemoveDirectory(name) != FALSE) {
 
213
    if (RemoveDirectoryW(wname) != FALSE) {
215
214
        return 1;
216
215
    }
217
216
    errno = errno_map(GetLastError());
218
217
    if (errno == EACCES) {
219
 
        attr = GetFileAttributes(name);
 
218
        attr = GetFileAttributesW(wname);
220
219
        if (attr != (DWORD) -1) {
221
220
            if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
222
221
                /* 
238
237
            GetVersionEx(&os);
239
238
            if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
240
239
                HANDLE handle;
241
 
                WIN32_FIND_DATA data;
242
 
                char buffer[2*MAX_PATH];
 
240
                WIN32_FIND_DATAW data;
 
241
                WCHAR buffer[2*MAX_PATH];
243
242
                int len;
244
243
 
245
 
                len = strlen(name);
246
 
                strcpy(buffer, name);
247
 
                if (buffer[0] && buffer[len-1] != '\\' && buffer[len-1] != '/') {
248
 
                    strcat(buffer, "\\");
 
244
                len = wcslen(wname);
 
245
                wcscpy(buffer, wname);
 
246
                if (buffer[0] && buffer[len-1] != L'\\' && buffer[len-1] != L'/') {
 
247
                    wcscat(buffer, L"\\");
249
248
                }
250
 
                strcat(buffer, "*.*");
251
 
                handle = FindFirstFile(buffer, &data);
 
249
                wcscat(buffer, L"*.*");
 
250
                handle = FindFirstFileW(buffer, &data);
252
251
                if (handle != INVALID_HANDLE_VALUE) {
253
252
                    while (1) {
254
 
                        if ((strcmp(data.cFileName, ".") != 0)
255
 
                                && (strcmp(data.cFileName, "..") != 0)) {
 
253
                        if ((wcscmp(data.cFileName, L".") != 0)
 
254
                                && (wcscmp(data.cFileName, L"..") != 0)) {
256
255
                            /*
257
256
                             * Found something in this directory.
258
257
                             */
260
259
                            errno = EEXIST;
261
260
                            break;
262
261
                        }
263
 
                        if (FindNextFile(handle, &data) == FALSE) {
 
262
                        if (FindNextFileW(handle, &data) == FALSE) {
264
263
                            break;
265
264
                        }
266
265
                    }
284
283
}
285
284
 
286
285
int
287
 
efile_delete_file(errInfo, name)
288
 
Efile_error* errInfo;           /* Where to return error codes. */
289
 
char* name;                     /* Name of file to delete. */
 
286
efile_delete_file(Efile_error* errInfo,         /* Where to return error codes. */
 
287
                  char* name)                   /* Name of file to delete. */
290
288
{
291
289
    DWORD attr;
 
290
    WCHAR *wname = (WCHAR *) name;
292
291
 
293
 
    if (DeleteFile(name) != FALSE) {
 
292
    if (DeleteFileW(wname) != FALSE) {
294
293
        return 1;
295
294
    }
296
295
 
297
296
    errno = errno_map(GetLastError());
298
297
    if (errno == EACCES) {
299
 
        attr = GetFileAttributes(name);
 
298
        attr = GetFileAttributesW(wname);
300
299
        if (attr != (DWORD) -1) {
301
300
            if (attr & FILE_ATTRIBUTE_DIRECTORY) {
302
301
                /*
308
307
            }
309
308
        }
310
309
    } else if (errno == ENOENT) {
311
 
        attr = GetFileAttributes(name);
 
310
        attr = GetFileAttributesW(wname);
312
311
        if (attr != (DWORD) -1) {
313
312
            if (attr & FILE_ATTRIBUTE_DIRECTORY) {
314
313
                /*
362
361
 */
363
362
 
364
363
int
365
 
efile_rename(errInfo, src, dst)
366
 
Efile_error* errInfo;           /* Where to return error codes. */
367
 
char* src;                      /* Original name. */
368
 
char* dst;                      /* New name. */
 
364
efile_rename(Efile_error* errInfo,      /* Where to return error codes. */
 
365
             char* src,                 /* Original name. */
 
366
             char* dst)                 /* New name. */
369
367
{
370
368
    DWORD srcAttr, dstAttr;
 
369
    WCHAR *wsrc = (WCHAR *) src;
 
370
    WCHAR *wdst = (WCHAR *) dst;
371
371
    
372
 
    if (MoveFile(src, dst) != FALSE) {
 
372
    if (MoveFileW(wsrc, wdst) != FALSE) {
373
373
        return 1;
374
374
    }
375
375
 
376
376
    errno = errno_map(GetLastError());
377
 
    srcAttr = GetFileAttributes(src);
378
 
    dstAttr = GetFileAttributes(dst);
 
377
    srcAttr = GetFileAttributesW(wsrc);
 
378
    dstAttr = GetFileAttributesW(wdst);
379
379
    if (srcAttr == (DWORD) -1) {
380
380
        srcAttr = 0;
381
381
    }
390
390
    if (errno == EACCES) {
391
391
        decode:
392
392
        if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
393
 
            char srcPath[MAX_PATH], dstPath[MAX_PATH];
394
 
            char *srcRest, *dstRest;
 
393
            WCHAR srcPath[MAX_PATH], dstPath[MAX_PATH];
 
394
            WCHAR *srcRest, *dstRest;
395
395
            int size;
396
396
 
397
 
            size = GetFullPathName(src, sizeof(srcPath), srcPath, &srcRest);
398
 
            if ((size == 0) || (size > sizeof(srcPath))) {
 
397
            size = GetFullPathNameW(wsrc, MAX_PATH, srcPath, &srcRest);
 
398
            if ((size == 0) || (size > MAX_PATH)) {
399
399
                return check_error(-1, errInfo);
400
400
            }
401
 
            size = GetFullPathName(dst, sizeof(dstPath), dstPath, &dstRest);
402
 
            if ((size == 0) || (size > sizeof(dstPath))) {
 
401
            size = GetFullPathNameW(wdst, MAX_PATH, dstPath, &dstRest);
 
402
            if ((size == 0) || (size > MAX_PATH)) {
403
403
                return check_error(-1, errInfo);
404
404
            }
405
405
            if (srcRest == NULL) {
406
 
                srcRest = srcPath + strlen(srcPath);
 
406
                srcRest = srcPath + wcslen(srcPath);
407
407
            }
408
 
            if (strnicmp(srcPath, dstPath, srcRest - srcPath) == 0) {
 
408
            if (_wcsnicmp(srcPath, dstPath, srcRest - srcPath) == 0) {
409
409
                /*
410
410
                 * Trying to move a directory into itself.
411
411
                 */
420
420
            }
421
421
 
422
422
            (void) extract_root(dstPath);
423
 
            if (dstPath[0] == '\0') {
 
423
            if (dstPath[0] == L'\0') {
424
424
                /*
425
425
                 * The filename was invalid.  (Don't know why,
426
426
                 * but play it safe.)
427
427
                 */
428
428
                errno = EINVAL;
429
429
            }
430
 
            if (stricmp(srcPath, dstPath) != 0) {
 
430
            if (_wcsicmp(srcPath, dstPath) != 0) {
431
431
                /*
432
432
                 * If src is a directory and dst filesystem != src
433
433
                 * filesystem, errno should be EXDEV.  It is very
463
463
                 * fails, it's because it wasn't empty.
464
464
                 */
465
465
 
466
 
                if (RemoveDirectory(dst)) {
 
466
                if (RemoveDirectoryW(wdst)) {
467
467
                    /*
468
468
                     * Now that that empty directory is gone, we can try
469
469
                     * renaming again.  If that fails, we'll put this empty
470
470
                     * directory back, for completeness.
471
471
                     */
472
472
 
473
 
                    if (MoveFile(src, dst) != FALSE) {
 
473
                    if (MoveFileW(wsrc, wdst) != FALSE) {
474
474
                        return 1;
475
475
                    }
476
476
 
480
480
                     */
481
481
 
482
482
                    errno = errno_map(GetLastError());
483
 
                    CreateDirectory(dst, NULL);
484
 
                    SetFileAttributes(dst, dstAttr);
 
483
                    CreateDirectoryW(wdst, NULL);
 
484
                    SetFileAttributesW(wdst, dstAttr);
485
485
                    if (errno == EACCES) {
486
486
                        /*
487
487
                         * Decode the EACCES to a more meaningful error.
506
506
                 *    put temp file back to old name.
507
507
                 */
508
508
 
509
 
                char tempName[MAX_PATH];
 
509
                WCHAR tempName[MAX_PATH];
510
510
                int result, size;
511
 
                char *rest;
 
511
                WCHAR *rest;
512
512
                
513
 
                size = GetFullPathName(dst, sizeof(tempName), tempName, &rest);
514
 
                if ((size == 0) || (size > sizeof(tempName)) || (rest == NULL)) {
 
513
                size = GetFullPathNameW(wdst, MAX_PATH, tempName, &rest);
 
514
                if ((size == 0) || (size > MAX_PATH) || (rest == NULL)) {
515
515
                    return check_error(-1, errInfo);
516
516
                }
517
 
                *rest = '\0';
 
517
                *rest = L'\0';
518
518
                result = -1;
519
 
                if (GetTempFileName(tempName, "erlr", 0, tempName) != 0) {
 
519
                if (GetTempFileNameW(tempName, L"erlr", 0, tempName) != 0) {
520
520
                    /*
521
521
                     * Strictly speaking, need the following DeleteFile and
522
522
                     * MoveFile to be joined as an atomic operation so no
524
524
                     * same temp file.
525
525
                     */
526
526
                     
527
 
                    DeleteFile(tempName);
528
 
                    if (MoveFile(dst, tempName) != FALSE) {
529
 
                        if (MoveFile(src, dst) != FALSE) {
530
 
                            SetFileAttributes(tempName, FILE_ATTRIBUTE_NORMAL);
531
 
                            DeleteFile(tempName);
 
527
                    DeleteFileW(tempName);
 
528
                    if (MoveFileW(wdst, tempName) != FALSE) {
 
529
                        if (MoveFileW(wsrc, wdst) != FALSE) {
 
530
                            SetFileAttributesW(tempName, FILE_ATTRIBUTE_NORMAL);
 
531
                            DeleteFileW(tempName);
532
532
                            return 1;
533
533
                        } else {
534
 
                            DeleteFile(dst);
535
 
                            MoveFile(tempName, dst);
 
534
                            DeleteFileW(wdst);
 
535
                            MoveFileW(tempName, wdst);
536
536
                        }
537
537
                    } 
538
538
 
558
558
}
559
559
 
560
560
int
561
 
efile_chdir(errInfo, name)
562
 
Efile_error* errInfo;           /* Where to return error codes. */
563
 
char* name;                     /* Name of directory to make current. */
 
561
efile_chdir(Efile_error* errInfo,       /* Where to return error codes. */
 
562
            char* name)                 /* Name of directory to make current. */
564
563
{
565
 
    int success = check_error(chdir(name), errInfo);
 
564
    int success = check_error(_wchdir((WCHAR *) name), errInfo);
566
565
    if (!success && errInfo->posix_errno == EINVAL)
567
566
        /* POSIXification of errno */
568
567
        errInfo->posix_errno = ENOENT;
570
569
}
571
570
 
572
571
int
573
 
efile_getdcwd(errInfo, drive, buffer, size)
574
 
Efile_error* errInfo;           /* Where to return error codes. */
575
 
int drive;                      /* 0 - current, 1 - A, 2 - B etc. */
576
 
char* buffer;                   /* Where to return the current directory. */
577
 
size_t size;                    /* Size of buffer. */
 
572
efile_getdcwd(Efile_error* errInfo,             /* Where to return error codes. */
 
573
              int drive,                        /* 0 - current, 1 - A, 2 - B etc. */
 
574
              char* buffer,                     /* Where to return the current directory. */
 
575
              size_t size)                      /* Size of buffer. */
578
576
{
579
 
    if (_getdcwd(drive, buffer, size) == NULL)
 
577
    WCHAR *wbuffer = (WCHAR *) buffer;
 
578
    size_t wbuffer_size = size / 2; 
 
579
    if (_wgetdcwd(drive, wbuffer, wbuffer_size) == NULL)
580
580
        return check_error(-1, errInfo);
581
 
    for ( ; *buffer; buffer++) 
582
 
        if (*buffer == '\\')
583
 
            *buffer = '/';
 
581
    for ( ; *wbuffer; wbuffer++) 
 
582
        if (*wbuffer == L'\\')
 
583
            *wbuffer = L'/';
584
584
    return 1;
585
585
}
586
586
 
587
587
int
588
 
efile_readdir(errInfo, name, dir_handle, buffer, size)
589
 
Efile_error* errInfo;           /* Where to return error codes. */
590
 
char* name;                     /* Name of directory to open. */
591
 
EFILE_DIR_HANDLE* dir_handle;   /* Directory handle of open directory. */
592
 
char* buffer;                   /* Pointer to buffer for one filename. */
593
 
size_t size;                    /* Size of buffer. */
 
588
efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
 
589
              char* name,           /* Name of directory to list */
 
590
              EFILE_DIR_HANDLE* dir_handle, /* Handle of opened directory or NULL */
 
591
              char* buffer,                 /* Buffer to put one filename in */ 
 
592
              size_t *size)                 /* in-out size of buffer/size of filename excluding zero
 
593
                                               termination in bytes*/
594
594
{
595
595
    HANDLE dir;                 /* Handle to directory. */
596
 
    char wildcard[MAX_PATH];    /* Wildcard to search for. */
597
 
    WIN32_FIND_DATA findData;   /* Data found by FindFirstFile() or FindNext(). */
 
596
    WCHAR wildcard[MAX_PATH];   /* Wildcard to search for. */
 
597
    WIN32_FIND_DATAW findData;  /* Data found by FindFirstFile() or FindNext(). */
 
598
    /* Alignment is not honored, this works on x86 because of alignment fixup by processor.
 
599
       Not perfect, but faster than alinging by hand (really) */
 
600
    WCHAR *wname = (WCHAR *) name;
 
601
    WCHAR *wbuffer = (WCHAR *) buffer;
598
602
 
599
603
    /*
600
604
     * First time we must setup everything.
601
605
     */
602
606
 
603
607
    if (*dir_handle == NULL) {
604
 
        int length = strlen(name);
605
 
        char* s;
 
608
        int length = wcslen(wname);
 
609
        WCHAR* s;
606
610
 
607
611
        if (length+3 >= MAX_PATH) {
608
612
            errno = ENAMETOOLONG;
609
613
            return check_error(-1, errInfo);
610
614
        }
611
615
 
612
 
        strcpy(wildcard, name);
 
616
        wcscpy(wildcard, wname);
613
617
        s = wildcard+length-1;
614
 
        if (*s != '/' && *s != '\\')
615
 
            *++s = '\\';
616
 
        *++s = '*';
617
 
        *++s = '\0';
618
 
        DEBUGF(("Reading %s\n", wildcard));
619
 
        dir = FindFirstFile(wildcard, &findData);
 
618
        if (*s != L'/' && *s != L'\\')
 
619
            *++s = L'\\';
 
620
        *++s = L'*';
 
621
        *++s = L'\0';
 
622
        DEBUGF(("Reading %ws\n", wildcard));
 
623
        dir = FindFirstFileW(wildcard, &findData);
620
624
        if (dir == INVALID_HANDLE_VALUE)
621
625
            return set_error(errInfo);
622
626
        *dir_handle = (EFILE_DIR_HANDLE) dir;
623
627
 
624
628
        if (!IS_DOT_OR_DOTDOT(findData.cFileName)) {
625
 
            strcpy(buffer, findData.cFileName);
 
629
            wcscpy(wbuffer, findData.cFileName);
 
630
            *size = wcslen(wbuffer)*2;
626
631
            return 1;
627
632
        }
628
633
    }
635
640
    dir = (HANDLE) *dir_handle;
636
641
 
637
642
    for (;;) {
638
 
        if (FindNextFile(dir, &findData)) {
 
643
        if (FindNextFileW(dir, &findData)) {
639
644
            if (IS_DOT_OR_DOTDOT(findData.cFileName))
640
645
                continue;
641
 
            strcpy(buffer, findData.cFileName);
 
646
            wcscpy(wbuffer, findData.cFileName);
 
647
            *size = wcslen(wbuffer)*2;
642
648
            return 1;
643
649
        }
644
650
 
655
661
}
656
662
 
657
663
int
658
 
efile_openfile(errInfo, name, flags, pfd, pSize)
659
 
Efile_error* errInfo;           /* Where to return error codes. */
660
 
char* name;                     /* Name of directory to open. */
661
 
int flags;                      /* Flags to use for opening. */
662
 
int* pfd;                       /* Where to store the file descriptor. */
663
 
Sint64* pSize;                  /* Where to store the size of the file. */
 
664
efile_openfile(Efile_error* errInfo,            /* Where to return error codes. */
 
665
               char* name,                      /* Name of directory to open. */
 
666
               int flags,                       /* Flags to use for opening. */
 
667
               int* pfd,                        /* Where to store the file descriptor. */
 
668
               Sint64* pSize)                   /* Where to store the size of the file. */
664
669
{
665
670
    BY_HANDLE_FILE_INFORMATION fileInfo; /* File information from a handle. */
666
671
    HANDLE fd;                  /* Handle to open file. */
667
672
    DWORD access;               /* Access mode: GENERIC_READ, GENERIC_WRITE. */
668
673
    DWORD crFlags;
 
674
    WCHAR *wname = (WCHAR *) name;
669
675
 
670
676
    switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) {
671
677
    case EFILE_MODE_READ:
689
695
    if (flags & EFILE_MODE_APPEND) {
690
696
        crFlags = OPEN_ALWAYS;
691
697
    }
692
 
    fd = CreateFile(name, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
 
698
    if (flags & EFILE_MODE_EXCL) {
 
699
        crFlags = CREATE_NEW;
 
700
    }
 
701
    fd = CreateFileW(wname, access,
 
702
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
693
703
                    NULL, crFlags, FILE_ATTRIBUTE_NORMAL, NULL);
694
704
 
695
705
    /*
707
717
         * to EISDIR.
708
718
         */
709
719
        if (errInfo->posix_errno && 
710
 
            (attr = GetFileAttributes(name)) != INVALID_FILE_ATTRIBUTES && 
 
720
            (attr = GetFileAttributesW(wname)) != INVALID_FILE_ATTRIBUTES && 
711
721
            (attr & FILE_ATTRIBUTE_DIRECTORY)) {
712
722
            errInfo->posix_errno = EISDIR;
713
723
        }
731
741
 
732
742
int 
733
743
efile_may_openfile(Efile_error* errInfo, char *name) {
 
744
    WCHAR *wname = (WCHAR *) name;
734
745
    DWORD attr;
735
746
 
736
 
    if ((attr = GetFileAttributes(name)) == INVALID_FILE_ATTRIBUTES) {
 
747
    if ((attr = GetFileAttributesW(wname)) == INVALID_FILE_ATTRIBUTES) {
737
748
        return check_error(-1, errInfo);
738
749
    }
739
750
 
742
753
        return check_error(-1, errInfo);
743
754
    }
744
755
    return 1;
745
 
#if 0
746
 
    struct stat statbuf;
747
 
    
748
 
    if (stat(name, &statbuf)) {
749
 
        return check_error(-1, errInfo);
750
 
    }
751
 
    if (ISDIR(statbuf)) {
752
 
        errno = EISDIR;
753
 
        return check_error(-1, errInfo);
754
 
    }
755
 
    return 1;
756
 
#endif
757
756
}
758
757
 
759
758
void
764
763
}
765
764
 
766
765
int
 
766
efile_fdatasync(errInfo, fd)
 
767
Efile_error* errInfo;           /* Where to return error codes. */
 
768
int fd;                         /* File descriptor for file to sync. */
 
769
{
 
770
    /* Not available in Windows, just call regular fsync */
 
771
    return efile_fsync(errInfo, fd);
 
772
}
 
773
 
 
774
int
767
775
efile_fsync(errInfo, fd)
768
776
Efile_error* errInfo;           /* Where to return error codes. */
769
777
int fd;                         /* File descriptor for file to sync. */
779
787
               char* orig_name, int info_for_link)
780
788
{
781
789
    HANDLE findhandle;          /* Handle returned by FindFirstFile(). */
782
 
    WIN32_FIND_DATA findbuf;    /* Data return by FindFirstFile(). */
783
 
    char name[_MAX_PATH];
 
790
    WIN32_FIND_DATAW findbuf;   /* Data return by FindFirstFile(). */
 
791
    WCHAR name[_MAX_PATH];
784
792
    int name_len;
785
 
    char* path;
786
 
    char pathbuf[_MAX_PATH];
 
793
    WCHAR *path;
 
794
    WCHAR pathbuf[_MAX_PATH];
787
795
    int drive;                  /* Drive for filename (1 = A:, 2 = B: etc). */
 
796
    WCHAR *worig_name = (WCHAR *) orig_name; 
788
797
 
789
798
    /* Don't allow wildcards to be interpreted by system */
790
799
 
791
 
    if (strpbrk(orig_name, "?*")) {
 
800
    if (wcspbrk(worig_name, L"?*")) {
792
801
    enoent:
793
802
        errInfo->posix_errno = ENOENT;
794
803
        errInfo->os_errno = ERROR_FILE_NOT_FOUND;
800
809
     * slash, because it causes FindFirstFile() to fail on Win95.
801
810
     */
802
811
 
803
 
    if ((name_len = strlen(orig_name)) >= _MAX_PATH) {
 
812
    if ((name_len = wcslen(worig_name)) >= _MAX_PATH) {
804
813
        goto enoent;
805
814
    } else {
806
 
        strcpy(name, orig_name);
 
815
        wcscpy(name, worig_name);
807
816
        if (name_len > 2 && ISSLASH(name[name_len-1]) &&
808
 
            name[name_len-2] != ':') {
809
 
            name[name_len-1] = '\0';
 
817
            name[name_len-2] != L':') {
 
818
            name[name_len-1] = L'\0';
810
819
        }
811
820
    }
812
821
    
813
822
    /* Try to get disk from name.  If none, get current disk.  */
814
823
 
815
 
    if (name[1] != ':') {
 
824
    if (name[1] != L':') {
816
825
        drive = 0;
817
 
        if (GetCurrentDirectory(sizeof(pathbuf), pathbuf) &&
818
 
            pathbuf[1] == ':') {
819
 
            drive = tolower(pathbuf[0]) - 'a' + 1;
 
826
        if (GetCurrentDirectoryW(_MAX_PATH, pathbuf) &&
 
827
            pathbuf[1] == L':') {
 
828
            drive = towlower(pathbuf[0]) - L'a' + 1;
820
829
        }
821
 
    } else if (*name && name[2] == '\0') {
 
830
    } else if (*name && name[2] == L'\0') {
822
831
        /*
823
832
         * X: and nothing more is an error.
824
833
         */
826
835
        errInfo->os_errno = ERROR_FILE_NOT_FOUND;
827
836
        return 0;
828
837
    } else
829
 
        drive = tolower(*name) - 'a' + 1;
 
838
        drive = towlower(*name) - L'a' + 1;
830
839
 
831
 
    findhandle = FindFirstFile(name, &findbuf);
 
840
    findhandle = FindFirstFileW(name, &findbuf);
832
841
    if (findhandle == INVALID_HANDLE_VALUE) {
833
 
        if (!(strpbrk(name, "./\\") &&
834
 
              (path = _fullpath(pathbuf, name, _MAX_PATH)) &&
 
842
        if (!(wcspbrk(name, L"./\\") &&
 
843
              (path = _wfullpath(pathbuf, name, _MAX_PATH)) &&
835
844
              /* root dir. ('C:\') or UNC root dir. ('\\server\share\') */
836
 
              ((strlen(path) == 3) || IsRootUNCName(path)) &&
837
 
              (GetDriveType(path) > 1)   ) ) {
 
845
              ((wcslen(path) == 3) || is_root_unc_name(path)) &&
 
846
              (GetDriveTypeW(path) > 1)   ) ) {
838
847
            errInfo->posix_errno = ENOENT;
839
848
            errInfo->os_errno = ERROR_FILE_NOT_FOUND;
840
849
            return 0;
847
856
        findbuf.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
848
857
        findbuf.nFileSizeHigh = 0;
849
858
        findbuf.nFileSizeLow = 0;
850
 
        findbuf.cFileName[0] = '\0';
 
859
        findbuf.cFileName[0] = L'\0';
851
860
 
 
861
        pInfo->links = 1;
852
862
        pInfo->modifyTime.year = 1980;
853
863
        pInfo->modifyTime.month = 1;
854
864
        pInfo->modifyTime.day = 1;
861
871
        SYSTEMTIME SystemTime;
862
872
        FILETIME LocalFTime;
863
873
 
 
874
        /*first check if we are a symlink */
 
875
        if (!info_for_link && (findbuf.dwFileAttributes &
 
876
                               FILE_ATTRIBUTE_REPARSE_POINT)){
 
877
            /*
 
878
             * given that we know this is a symlink,
 
879
             we should be able to find its target */
 
880
            WCHAR target_name[_MAX_PATH];
 
881
            if (efile_readlink(errInfo, (char *) name, 
 
882
                               (char *) target_name,256) == 1) {
 
883
                FindClose(findhandle);
 
884
                return efile_fileinfo(errInfo, pInfo,
 
885
                                      (char *) target_name, info_for_link);
 
886
            }
 
887
        }
 
888
 
 
889
        /* number of links: */
 
890
        {
 
891
            HANDLE handle;      /* Handle returned by CreateFile() */
 
892
            BY_HANDLE_FILE_INFORMATION fileInfo; /* from  CreateFile() */
 
893
            if (handle = CreateFileW(name, GENERIC_READ, 0,NULL,
 
894
                                    OPEN_EXISTING, 0, NULL)) {
 
895
                GetFileInformationByHandle(handle, &fileInfo);
 
896
                pInfo->links = fileInfo.nNumberOfLinks;
 
897
                CloseHandle(handle);
 
898
            } else {
 
899
                pInfo->links = 1;
 
900
            }   
 
901
        }
 
902
 
864
903
#define GET_TIME(dst, src) \
865
904
if (!FileTimeToLocalFileTime(&findbuf.src, &LocalFTime) || \
866
905
    !FileTimeToSystemTime(&LocalFTime, &SystemTime)) { \
895
934
    pInfo->size_low = findbuf.nFileSizeLow;
896
935
    pInfo->size_high = findbuf.nFileSizeHigh;
897
936
        
898
 
    if (findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 
937
    if (info_for_link && (findbuf.dwFileAttributes &
 
938
                          FILE_ATTRIBUTE_REPARSE_POINT))
 
939
        pInfo->type = FT_SYMLINK;
 
940
    else if (findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
899
941
        pInfo->type = FT_DIRECTORY;
900
942
    else
901
943
        pInfo->type = FT_REGULAR;
906
948
        pInfo->access = FA_READ|FA_WRITE;
907
949
 
908
950
    pInfo->mode = dos_to_posix_mode(findbuf.dwFileAttributes, name);
909
 
    pInfo->links = 1;
910
951
    pInfo->major_device = drive;
911
952
    pInfo->minor_device = 0;
912
953
    pInfo->inode = 0;
917
958
}
918
959
 
919
960
int
920
 
efile_write_info(errInfo, pInfo, name)
921
 
Efile_error* errInfo;
922
 
Efile_info* pInfo;
923
 
char* name;
 
961
efile_write_info(Efile_error* errInfo,
 
962
                 Efile_info* pInfo,
 
963
                 char* name)
924
964
{
925
965
    SYSTEMTIME timebuf;
926
966
    FILETIME LocalFileTime;
934
974
    DWORD attr;
935
975
    DWORD tempAttr;
936
976
    BOOL modifyTime = FALSE;
 
977
    WCHAR *wname = (WCHAR *) name;
937
978
 
938
979
    /*
939
980
     * Get the attributes for the file.
940
981
     */
941
982
 
942
 
    tempAttr = attr = GetFileAttributes((LPTSTR)name);
 
983
    tempAttr = attr = GetFileAttributesW(wname);
943
984
    if (attr == 0xffffffff) {
944
985
        return set_error(errInfo);
945
986
    }
975
1016
     } \
976
1017
    }
977
1018
 
978
 
    MKTIME(ModifyFileTime, pInfo->accessTime, mtime);
979
 
    MKTIME(AccessFileTime, pInfo->modifyTime, atime);
 
1019
    MKTIME(ModifyFileTime, pInfo->modifyTime, mtime);
 
1020
    MKTIME(AccessFileTime, pInfo->accessTime, atime);
980
1021
    MKTIME(CreationFileTime, pInfo->cTime, ctime);
981
1022
#undef MKTIME
982
1023
 
993
1034
 
994
1035
        if (tempAttr & FILE_ATTRIBUTE_READONLY) {
995
1036
            tempAttr &= ~FILE_ATTRIBUTE_READONLY;
996
 
            if (!SetFileAttributes((LPTSTR) name, tempAttr)) {
 
1037
            if (!SetFileAttributesW(wname, tempAttr)) {
997
1038
                return set_error(errInfo);
998
1039
            }
999
1040
        }
1000
1041
 
1001
 
        fd = CreateFile(name, GENERIC_READ|GENERIC_WRITE,
 
1042
        fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE,
1002
1043
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
1003
1044
                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1004
1045
        if (fd != INVALID_HANDLE_VALUE) {
1016
1057
     */
1017
1058
 
1018
1059
    if (tempAttr != attr) {
1019
 
        if (!SetFileAttributes((LPTSTR) name, attr)) {
 
1060
        if (!SetFileAttributesW(wname, attr)) {
1020
1061
            return set_error(errInfo);
1021
1062
        }
1022
1063
    }
1069
1110
size_t count;                   /* Number of bytes to write. */
1070
1111
{
1071
1112
    DWORD written;              /* Bytes written in last operation. */
 
1113
    OVERLAPPED overlapped;
 
1114
    OVERLAPPED* pOverlapped = NULL;
1072
1115
 
1073
1116
    if (flags & EFILE_MODE_APPEND) {
1074
 
        (void) SetFilePointer((HANDLE) fd, 0, NULL, FILE_END);
 
1117
        memset(&overlapped, 0, sizeof(overlapped));
 
1118
        overlapped.Offset = 0xffffffff;
 
1119
        overlapped.OffsetHigh = 0xffffffff;
 
1120
        pOverlapped = &overlapped;
1075
1121
    }
1076
1122
    while (count > 0) {
1077
 
        if (!WriteFile((HANDLE) fd, buf, count, &written, NULL))
 
1123
        if (!WriteFile((HANDLE) fd, buf, count, &written, pOverlapped))
1078
1124
            return set_error(errInfo);
1079
1125
        buf += written;
1080
1126
        count -= written;
1094
1140
             size_t size)            /* Number of bytes to write */
1095
1141
{
1096
1142
    int cnt;                         /* Buffers so far written */
 
1143
    OVERLAPPED overlapped;
 
1144
    OVERLAPPED* pOverlapped = NULL;
1097
1145
 
1098
1146
    ASSERT(iovcnt >= 0);
1099
1147
    
1100
1148
    if (flags & EFILE_MODE_APPEND) {
1101
 
        (void) SetFilePointer((HANDLE) fd, 0, NULL, FILE_END);
 
1149
        memset(&overlapped, 0, sizeof(overlapped));
 
1150
        overlapped.Offset = 0xffffffff;
 
1151
        overlapped.OffsetHigh = 0xffffffff;
 
1152
        pOverlapped = &overlapped;
1102
1153
    }
1103
1154
    for (cnt = 0; cnt < iovcnt; cnt++) {
1104
1155
        if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
1110
1161
                               iov[cnt].iov_base + p, 
1111
1162
                               iov[cnt].iov_len - p, 
1112
1163
                               &w, 
1113
 
                               NULL))
 
1164
                               pOverlapped))
1114
1165
                    return set_error(errInfo);
1115
1166
            }
1116
1167
        }
1182
1233
 
1183
1234
 
1184
1235
/*
1185
 
 * IsRootUNCName - returns TRUE if the argument is a UNC name specifying
 
1236
 * is_root_unc_name - returns TRUE if the argument is a UNC name specifying
1186
1237
 *      a root share.  That is, if it is of the form \\server\share\.
1187
1238
 *      This routine will also return true if the argument is of the
1188
1239
 *      form \\server\share (no trailing slash) but Win32 currently
1192
1243
 */
1193
1244
 
1194
1245
static int
1195
 
IsRootUNCName(const char* path)
 
1246
is_root_unc_name(const WCHAR *path)
1196
1247
{
1197
1248
    /*
1198
1249
     * If a root UNC name, path will start with 2 (but not 3) slashes
1199
1250
     */
1200
1251
 
1201
 
    if ((strlen(path) >= 5) /* minimum string is "//x/y" */
 
1252
    if ((wcslen(path) >= 5) /* minimum string is "//x/y" */
1202
1253
        && ISSLASH(path[0]) && ISSLASH(path[1]))
1203
1254
    {
1204
 
        const char * p = path + 2 ;
 
1255
        const WCHAR *p = path + 2;
1205
1256
 
1206
1257
        /*
1207
1258
         * find the slash between the server name and share name
1244
1295
 */
1245
1296
 
1246
1297
static int
1247
 
extract_root(char* name)
 
1298
extract_root(WCHAR* name)
1248
1299
{
1249
 
    int len = strlen(name);
 
1300
    int len = wcslen(name);
1250
1301
 
1251
 
    if (isalpha(name[0]) && name[1] == ':' && ISSLASH(name[2])) {
1252
 
        int c = name[3];
1253
 
        name[3] = '\0';
1254
 
        return c == '\0';
 
1302
    if (iswalpha(name[0]) && name[1] == L':' && ISSLASH(name[2])) {
 
1303
        WCHAR c = name[3];
 
1304
        name[3] = L'\0';
 
1305
        return c == L'\0';
1255
1306
    } else if (len < 5 || !ISSLASH(name[0]) || !ISSLASH(name[1])) {
1256
1307
        goto error;
1257
1308
    } else {                    /* Try to find the end of the UNC name. */
1258
 
        char* p;
1259
 
        int c;
 
1309
        WCHAR* p;
 
1310
        WCHAR c;
1260
1311
 
1261
1312
        /*
1262
1313
         * Find the slash between the server name and share name.
1265
1316
        for (p = name + 2; *p; p++)
1266
1317
            if (ISSLASH(*p))
1267
1318
                break;
1268
 
        if (*p == '\0')
 
1319
        if (*p == L'\0')
1269
1320
            goto error;
1270
1321
 
1271
1322
        /*
1276
1327
            if (ISSLASH(*p))
1277
1328
                break;
1278
1329
        c = *p;
1279
 
        *p = '\0';
1280
 
        return c == '\0' || p[1] == '\0';
 
1330
        *p = L'\0';
 
1331
        return c == L'\0' || p[1] == L'\0';
1281
1332
    }
1282
1333
 
1283
1334
 error:
1284
 
    *name = '\0';
 
1335
    *name = L'\0';
1285
1336
    return 1;
1286
1337
}
1287
1338
 
1288
1339
static unsigned short
1289
 
dos_to_posix_mode(int attr, const char *name)
 
1340
dos_to_posix_mode(int attr, const WCHAR *name)
1290
1341
{
1291
1342
    register unsigned short uxmode;
1292
1343
    unsigned dosmode;
1293
 
    register const char *p;
 
1344
    register const WCHAR *p;
1294
1345
 
1295
1346
    dosmode = attr & 0xff;
1296
 
    if ((p = name)[1] == ':')
 
1347
    if ((p = name)[1] == L':')
1297
1348
        p += 2;
1298
1349
 
1299
1350
    /* check to see if this is a directory - note we must make a special
1302
1353
 
1303
1354
    uxmode = (unsigned short)
1304
1355
        (((ISSLASH(*p) && !p[1]) || (dosmode & FILE_ATTRIBUTE_DIRECTORY) ||
1305
 
               *p == '\0') ? _S_IFDIR|_S_IEXEC : _S_IFREG);
 
1356
               *p == L'\0') ? _S_IFDIR|_S_IEXEC : _S_IFREG);
1306
1357
 
1307
1358
    /* If attribute byte does not have read-only bit, it is read-write */
1308
1359
 
1311
1362
 
1312
1363
    /* see if file appears to be executable - check extension of name */
1313
1364
 
1314
 
    if (p = strrchr(name, '.')) {
1315
 
        if (!stricmp(p, ".exe") ||
1316
 
            !stricmp(p, ".cmd") ||
1317
 
            !stricmp(p, ".bat") ||
1318
 
            !stricmp(p, ".com"))
 
1365
    if (p = wcsrchr(name, L'.')) {
 
1366
        if (!_wcsicmp(p, L".exe") ||
 
1367
            !_wcsicmp(p, L".cmd") ||
 
1368
            !_wcsicmp(p, L".bat") ||
 
1369
            !_wcsicmp(p, L".com"))
1319
1370
            uxmode |= _S_IEXEC;
1320
1371
    }
1321
1372
 
1330
1381
int
1331
1382
efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
1332
1383
{
 
1384
    /*
 
1385
     * load dll and see if we have CreateSymbolicLink at runtime:
 
1386
     * (Vista only)
 
1387
     */
 
1388
    HINSTANCE hModule = NULL;
 
1389
    WCHAR *wname = (WCHAR *) name;
 
1390
    WCHAR *wbuffer = (WCHAR *) buffer;
 
1391
    if ((hModule = LoadLibrary("kernel32.dll")) != NULL) {
 
1392
        typedef DWORD (WINAPI * GETFINALPATHNAMEBYHANDLEPTR)(
 
1393
                                                             HANDLE hFile,
 
1394
                                                             LPCWSTR lpFilePath,
 
1395
                                                             DWORD cchFilePath,
 
1396
                                                             DWORD dwFlags);
 
1397
 
 
1398
        GETFINALPATHNAMEBYHANDLEPTR pGetFinalPathNameByHandle =
 
1399
            (GETFINALPATHNAMEBYHANDLEPTR)GetProcAddress(hModule, "GetFinalPathNameByHandleW");
 
1400
 
 
1401
        if (pGetFinalPathNameByHandle == NULL) {
 
1402
            FreeLibrary(hModule);
 
1403
        } else {
 
1404
            /* first check if file is a symlink; {error, einval} otherwise */
 
1405
            DWORD fileAttributes =  GetFileAttributesW(wname);
 
1406
            if ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
 
1407
                BOOLEAN success = 0;
 
1408
                HANDLE h = CreateFileW(wname, GENERIC_READ, 0,NULL, OPEN_EXISTING, 0, NULL);
 
1409
                int len;
 
1410
                if(h != INVALID_HANDLE_VALUE) {
 
1411
                    success = pGetFinalPathNameByHandle(h, wbuffer, size,0);
 
1412
                    /* GetFinalPathNameByHandle prepends path with "\\?\": */
 
1413
                    len = wcslen(wbuffer);
 
1414
                    wmemmove(wbuffer,wbuffer+4,len-3);
 
1415
                    if (len - 4 >= 2 && wbuffer[1] == L':' && wbuffer[0] >= L'A' &&
 
1416
                        wbuffer[0] <= L'Z') {
 
1417
                        wbuffer[0] = wbuffer[0] + L'a' - L'A';
 
1418
                    }
 
1419
                        
 
1420
                    for ( ; *wbuffer; wbuffer++) 
 
1421
                        if (*wbuffer == L'\\')
 
1422
                            *wbuffer = L'/';
 
1423
                    CloseHandle(h);
 
1424
                }
 
1425
                FreeLibrary(hModule);
 
1426
                if (success) {
 
1427
                    return 1;
 
1428
                } else {
 
1429
                    return set_error(errInfo);
 
1430
                }
 
1431
            } else {
 
1432
                FreeLibrary(hModule);
 
1433
                errno = EINVAL;
 
1434
                return check_error(-1, errInfo);
 
1435
            }
 
1436
        }
 
1437
    }
1333
1438
    errno = ENOTSUP;
1334
1439
    return check_error(-1, errInfo);
1335
1440
}
1338
1443
int
1339
1444
efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size)
1340
1445
{
1341
 
    WIN32_FIND_DATA wfd;
 
1446
    WIN32_FIND_DATAW wfd;
1342
1447
    HANDLE fh;
1343
 
    char name[_MAX_PATH];
 
1448
    WCHAR name[_MAX_PATH+1];
1344
1449
    int name_len;
1345
 
    char* path;
1346
 
    char pathbuf[_MAX_PATH];
 
1450
    WCHAR* path;
 
1451
    WCHAR pathbuf[_MAX_PATH+1]; /* Unclear weather GetCurrentDirectory will access one char after
 
1452
                                   _MAX_PATH */
 
1453
    WCHAR *worig_name = (WCHAR *) orig_name;
 
1454
    WCHAR *wbuffer = (WCHAR *) buffer;
1347
1455
    int drive;                  /* Drive for filename (1 = A:, 2 = B: etc). */
1348
1456
 
1349
1457
    /* Don't allow wildcards to be interpreted by system */
1350
1458
 
1351
 
    if (strpbrk(orig_name, "?*")) {
 
1459
    if (wcspbrk(worig_name, L"?*")) {
1352
1460
    enoent:
1353
1461
        errInfo->posix_errno = ENOENT;
1354
1462
        errInfo->os_errno = ERROR_FILE_NOT_FOUND;
1360
1468
     * slash, because it causes FindFirstFile() to fail on Win95.
1361
1469
     */
1362
1470
 
1363
 
    if ((name_len = strlen(orig_name)) >= _MAX_PATH) {
 
1471
    if ((name_len = wcslen(worig_name)) >= _MAX_PATH) {
1364
1472
        goto enoent;
1365
1473
    } else {
1366
 
        strcpy(name, orig_name);
 
1474
        wcscpy(name, worig_name);
1367
1475
        if (name_len > 2 && ISSLASH(name[name_len-1]) &&
1368
 
            name[name_len-2] != ':') {
1369
 
            name[name_len-1] = '\0';
 
1476
            name[name_len-2] != L':') {
 
1477
            name[name_len-1] = L'\0';
1370
1478
        }
1371
1479
    }
1372
1480
    
1373
1481
    /* Try to get disk from name.  If none, get current disk.  */
1374
1482
 
1375
 
    if (name[1] != ':') {
 
1483
    if (name[1] != L':') {
1376
1484
        drive = 0;
1377
 
        if (GetCurrentDirectory(sizeof(pathbuf), pathbuf) &&
1378
 
            pathbuf[1] == ':') {
1379
 
            drive = tolower(pathbuf[0]) - 'a' + 1;
 
1485
        if (GetCurrentDirectoryW(_MAX_PATH, pathbuf) &&
 
1486
            pathbuf[1] == L':') {
 
1487
            drive = towlower(pathbuf[0]) - L'a' + 1;
1380
1488
        }
1381
 
    } else if (*name && name[2] == '\0') {
 
1489
    } else if (*name && name[2] == L'\0') {
1382
1490
        /*
1383
1491
         * X: and nothing more is an error.
1384
1492
         */
1385
1493
        goto enoent;
1386
1494
    } else {
1387
 
        drive = tolower(*name) - 'a' + 1;
 
1495
        drive = towlower(*name) - L'a' + 1;
1388
1496
    }
1389
 
    fh = FindFirstFile(name,&wfd);
 
1497
    fh = FindFirstFileW(name,&wfd);
1390
1498
    if (fh == INVALID_HANDLE_VALUE) {
1391
 
        if (!(strpbrk(name, "./\\") &&
1392
 
              (path = _fullpath(pathbuf, name, _MAX_PATH)) &&
 
1499
        if (!(wcspbrk(name, L"./\\") &&
 
1500
              (path = _wfullpath(pathbuf, name, _MAX_PATH)) &&
1393
1501
              /* root dir. ('C:\') or UNC root dir. ('\\server\share\') */
1394
 
              ((strlen(path) == 3) || IsRootUNCName(path)) &&
1395
 
              (GetDriveType(path) > 1)   ) ) {
 
1502
              ((wcslen(path) == 3) || is_root_unc_name(path)) &&
 
1503
              (GetDriveTypeW(path) > 1)   ) ) {
1396
1504
            errno = errno_map(GetLastError());
1397
1505
            return check_error(-1, errInfo);
1398
1506
        }
1399
1507
        /*
1400
1508
         * Root directories (such as C:\ or \\server\share\ are fabricated.
1401
1509
         */
1402
 
        strcpy(buffer,name);
 
1510
        wcscpy(wbuffer,name);
1403
1511
        return 1;
1404
1512
    }
1405
1513
        
1406
 
    strcpy(buffer,wfd.cAlternateFileName);
1407
 
    if (!*buffer) {
1408
 
        strcpy(buffer,wfd.cFileName);
 
1514
    wcscpy(wbuffer,wfd.cAlternateFileName);
 
1515
    if (!*wbuffer) {
 
1516
        wcscpy(wbuffer,wfd.cFileName);
1409
1517
    }
1410
 
 
 
1518
    FindClose(fh);
1411
1519
    return 1;
1412
1520
}
1413
1521
 
 
1522
 
1414
1523
int
1415
1524
efile_link(Efile_error* errInfo, char* old, char* new)
1416
1525
{
1417
 
    errno = ENOTSUP;
1418
 
    return check_error(-1, errInfo);
 
1526
    WCHAR *wold = (WCHAR *) old;
 
1527
    WCHAR *wnew = (WCHAR *) new;
 
1528
    if(!CreateHardLinkW(wnew, wold, NULL)) {
 
1529
        return set_error(errInfo);
 
1530
    }
 
1531
    return 1;
1419
1532
}
1420
1533
 
1421
1534
int
1422
1535
efile_symlink(Efile_error* errInfo, char* old, char* new)
1423
1536
{
 
1537
    /*
 
1538
     * Load dll and see if we have CreateSymbolicLink at runtime:
 
1539
     * (Vista only)
 
1540
     */
 
1541
    HINSTANCE hModule = NULL;
 
1542
    WCHAR *wold = (WCHAR *) old;
 
1543
    WCHAR *wnew = (WCHAR *) new;
 
1544
    if ((hModule = LoadLibrary("kernel32.dll")) != NULL) {
 
1545
        typedef BOOLEAN (WINAPI  * CREATESYMBOLICLINKFUNCPTR) (
 
1546
             LPCWSTR lpSymlinkFileName,
 
1547
             LPCWSTR lpTargetFileName,
 
1548
             DWORD dwFlags);
 
1549
 
 
1550
        CREATESYMBOLICLINKFUNCPTR pCreateSymbolicLink =
 
1551
            (CREATESYMBOLICLINKFUNCPTR) GetProcAddress(hModule,
 
1552
                                                       "CreateSymbolicLinkW");
 
1553
        /* A for MBCS, W for UNICODE... char* above implies 'W'! */
 
1554
        if (pCreateSymbolicLink != NULL) {
 
1555
            DWORD attr = GetFileAttributesW(wold);
 
1556
            int flag = (attr != INVALID_FILE_ATTRIBUTES &&
 
1557
                        attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
 
1558
            /*  SYMBOLIC_LINK_FLAG_DIRECTORY = 1 */
 
1559
            BOOLEAN success = pCreateSymbolicLink(wnew, wold, flag);
 
1560
            FreeLibrary(hModule);
 
1561
 
 
1562
            if (success) {
 
1563
                return 1;
 
1564
            } else {
 
1565
                return set_error(errInfo);
 
1566
            }
 
1567
        } else
 
1568
            FreeLibrary(hModule);
 
1569
    }
1424
1570
    errno = ENOTSUP;
1425
1571
    return check_error(-1, errInfo);
1426
1572
}
 
1573
 
 
1574
int
 
1575
efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
 
1576
            Sint64 length, int advise)
 
1577
{
 
1578
    /* posix_fadvise is not available on Windows, do nothing */
 
1579
    errno = ERROR_SUCCESS;
 
1580
    return check_error(0, errInfo);
 
1581
}