source: box/trunk/lib/win32/emu.cpp @ 2992

Revision 2992, 42.8 KB checked in by chris, 9 months ago (diff)

Use "more standard" Windows API functions FindFirstFileW and FindNextFileW
for directory enumeration instead of _wfindfirst and _wfindnext.

Ignore reparse points when enumerating directories to avoid infinite loops.

Convert VSS paths back to real paths when notifying users about backup
progress.

  • Property svn:eol-style set to native
Line 
1// Box Backup Win32 native port by Nick Knight
2
3#include "emu.h"
4
5#ifdef WIN32
6
7#include <assert.h>
8#include <fcntl.h>
9#include <process.h>
10#include <windows.h>
11
12#ifdef HAVE_UNISTD_H
13        #include <unistd.h>
14#endif
15
16#include <string>
17#include <list>
18#include <sstream>
19
20// message resource definitions for syslog()
21#include "messages.h"
22
23DWORD winerrno;
24struct passwd gTempPasswd;
25
26bool EnableBackupRights()
27{
28        HANDLE hToken;
29        TOKEN_PRIVILEGES token_priv;
30
31        //open current process to adjust privileges
32        if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, 
33                &hToken))
34        {
35                ::syslog(LOG_ERR, "Failed to open process token: %s",
36                        GetErrorMessage(GetLastError()).c_str());
37                return false;
38        }
39
40        //let's build the token privilege struct -
41        //first, look up the LUID for the backup privilege
42
43        if (!LookupPrivilegeValue(
44                NULL, //this system
45                SE_BACKUP_NAME, //the name of the privilege
46                &( token_priv.Privileges[0].Luid ))) //result
47        {
48                ::syslog(LOG_ERR, "Failed to lookup backup privilege: %s",
49                        GetErrorMessage(GetLastError()).c_str());
50                CloseHandle(hToken);
51                return false;
52        }
53
54        token_priv.PrivilegeCount = 1;
55        token_priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
56
57        // now set the privilege
58        // because we're going exit right after dumping the streams, there isn't
59        // any need to save current state
60
61        if (!AdjustTokenPrivileges(
62                hToken, //our process token
63                false,  //we're not disabling everything
64                &token_priv, //address of structure
65                sizeof(token_priv), //size of structure
66                NULL, NULL)) //don't save current state
67        {
68                //this function is a little tricky - if we were adjusting
69                //more than one privilege, it could return success but not
70                //adjust them all - in the general case, you need to trap this
71                ::syslog(LOG_ERR, "Failed to enable backup privilege: %s",
72                        GetErrorMessage(GetLastError()).c_str());
73                CloseHandle(hToken);
74                return false;
75
76        }
77
78        CloseHandle(hToken);
79        return true;
80}
81
82// --------------------------------------------------------------------------
83//
84// Function
85//              Name:    GetDefaultConfigFilePath(std::string name)
86//              Purpose: Calculates the default configuration file name,
87//                       by using the directory location of the currently
88//                       executing program, and appending the provided name.
89//                       In case of fire, returns an empty string.
90//              Created: 26th May 2007
91//
92// --------------------------------------------------------------------------
93std::string GetDefaultConfigFilePath(const std::string& rName)
94{
95        WCHAR exePathWide[MAX_PATH];
96        GetModuleFileNameW(NULL, exePathWide, MAX_PATH-1);
97
98        char* exePathUtf8 = ConvertFromWideString(exePathWide, CP_UTF8);
99        if (exePathUtf8 == NULL)
100        {
101                return "";
102        }
103
104        std::string configfile = exePathUtf8;
105        delete [] exePathUtf8;
106       
107        // make the default config file name,
108        // based on the program path
109        configfile = configfile.substr(0,
110                configfile.rfind('\\'));
111        configfile += "\\";
112        configfile += rName;
113
114        return configfile;
115}
116
117// --------------------------------------------------------------------------
118//
119// Function
120//              Name:    ConvertToWideString
121//              Purpose: Converts a string from specified codepage to
122//                       a wide string (WCHAR*). Returns a buffer which
123//                       MUST be freed by the caller with delete[].
124//                       In case of fire, logs the error and returns NULL.
125//              Created: 4th February 2006
126//
127// --------------------------------------------------------------------------
128WCHAR* ConvertToWideString(const char* pString, unsigned int codepage,
129        bool logErrors)
130{
131        int len = MultiByteToWideChar
132        (
133                codepage, // source code page
134                0,        // character-type options
135                pString,  // string to map
136                -1,       // number of bytes in string - auto detect
137                NULL,     // wide-character buffer
138                0         // size of buffer - work out
139                          //   how much space we need
140        );
141
142        if (len == 0)
143        {
144                winerrno = GetLastError();
145                if (logErrors)
146                {
147                        ::syslog(LOG_WARNING, 
148                                "Failed to convert string to wide string: "
149                                "%s", GetErrorMessage(winerrno).c_str());
150                }
151                errno = EINVAL;
152                return NULL;
153        }
154
155        WCHAR* buffer = new WCHAR[len];
156
157        if (buffer == NULL)
158        {
159                if (logErrors)
160                {
161                        ::syslog(LOG_WARNING, 
162                                "Failed to convert string to wide string: "
163                                "out of memory");
164                }
165                winerrno = ERROR_OUTOFMEMORY;
166                errno = ENOMEM;
167                return NULL;
168        }
169
170        len = MultiByteToWideChar
171        (
172                codepage, // source code page
173                0,        // character-type options
174                pString,  // string to map
175                -1,       // number of bytes in string - auto detect
176                buffer,   // wide-character buffer
177                len       // size of buffer
178        );
179
180        if (len == 0)
181        {
182                winerrno = GetLastError();
183                if (logErrors)
184                {
185                        ::syslog(LOG_WARNING, 
186                                "Failed to convert string to wide string: "
187                                "%s", GetErrorMessage(winerrno).c_str());
188                }
189                errno = EACCES;
190                delete [] buffer;
191                return NULL;
192        }
193
194        return buffer;
195}
196
197// --------------------------------------------------------------------------
198//
199// Function
200//              Name:    ConvertUtf8ToWideString
201//              Purpose: Converts a string from UTF-8 to a wide string.
202//                       Returns a buffer which MUST be freed by the caller
203//                       with delete[].
204//                       In case of fire, logs the error and returns NULL.
205//              Created: 4th February 2006
206//
207// --------------------------------------------------------------------------
208WCHAR* ConvertUtf8ToWideString(const char* pString)
209{
210        return ConvertToWideString(pString, CP_UTF8, true);
211}
212
213// --------------------------------------------------------------------------
214//
215// Function
216//              Name:    ConvertFromWideString
217//              Purpose: Converts a wide string to a narrow string in the
218//                       specified code page. Returns a buffer which MUST
219//                       be freed by the caller with delete[].
220//                       In case of fire, logs the error and returns NULL.
221//              Created: 4th February 2006
222//
223// --------------------------------------------------------------------------
224char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage)
225{
226        int len = WideCharToMultiByte
227        (
228                codepage, // destination code page
229                0,        // character-type options
230                pString,  // string to map
231                -1,       // number of bytes in string - auto detect
232                NULL,     // output buffer
233                0,        // size of buffer - work out
234                          //   how much space we need
235                NULL,     // replace unknown chars with system default
236                NULL      // don't tell us when that happened
237        );
238
239        if (len == 0)
240        {
241                ::syslog(LOG_WARNING, 
242                        "Failed to convert wide string to narrow: "
243                        "%s", GetErrorMessage(GetLastError()).c_str());
244                errno = EINVAL;
245                return NULL;
246        }
247
248        char* buffer = new char[len];
249
250        if (buffer == NULL)
251        {
252                ::syslog(LOG_WARNING, 
253                        "Failed to convert wide string to narrow: "
254                        "out of memory");
255                errno = ENOMEM;
256                return NULL;
257        }
258
259        len = WideCharToMultiByte
260        (
261                codepage, // source code page
262                0,        // character-type options
263                pString,  // string to map
264                -1,       // number of bytes in string - auto detect
265                buffer,   // output buffer
266                len,      // size of buffer
267                NULL,     // replace unknown chars with system default
268                NULL      // don't tell us when that happened
269        );
270
271        if (len == 0)
272        {
273                ::syslog(LOG_WARNING, 
274                        "Failed to convert wide string to narrow: "
275                        "%s", GetErrorMessage(GetLastError()).c_str());
276                errno = EACCES;
277                delete [] buffer;
278                return NULL;
279        }
280
281        return buffer;
282}
283
284bool ConvertFromWideString(const std::wstring& rInput, 
285        std::string* pOutput, unsigned int codepage)
286{
287        int len = WideCharToMultiByte
288        (
289                codepage, // destination code page
290                0,        // character-type options
291                rInput.c_str(),  // string to map
292                rInput.size(),       // number of bytes in string - auto detect
293                NULL,     // output buffer
294                0,        // size of buffer - work out
295                          //   how much space we need
296                NULL,     // replace unknown chars with system default
297                NULL      // don't tell us when that happened
298        );
299
300        if (len == 0)
301        {
302                ::syslog(LOG_WARNING, 
303                        "Failed to convert wide string to narrow: "
304                        "%s", GetErrorMessage(GetLastError()).c_str());
305                errno = EINVAL;
306                return false;
307        }
308
309        char* buffer = new char[len];
310
311        if (buffer == NULL)
312        {
313                ::syslog(LOG_WARNING, 
314                        "Failed to convert wide string to narrow: "
315                        "out of memory");
316                errno = ENOMEM;
317                return false;
318        }
319
320        len = WideCharToMultiByte
321        (
322                codepage, // source code page
323                0,        // character-type options
324                rInput.c_str(),  // string to map
325                rInput.size(),       // number of bytes in string - auto detect
326                buffer,   // output buffer
327                len,      // size of buffer
328                NULL,     // replace unknown chars with system default
329                NULL      // don't tell us when that happened
330        );
331
332        if (len == 0)
333        {
334                ::syslog(LOG_WARNING, 
335                        "Failed to convert wide string to narrow: "
336                        "%s", GetErrorMessage(GetLastError()).c_str());
337                errno = EACCES;
338                delete [] buffer;
339                return false;
340        }
341
342        *pOutput = std::string(buffer, len);
343        delete [] buffer;
344        return true;
345}
346
347// --------------------------------------------------------------------------
348//
349// Function
350//              Name:    ConvertEncoding(const std::string&, int,
351//                       std::string&, int)
352//              Purpose: Converts a string from one code page to another.
353//                       On success, replaces contents of rDest and returns
354//                       true. In case of fire, logs the error and returns
355//                       false.
356//              Created: 15th October 2006
357//
358// --------------------------------------------------------------------------
359bool ConvertEncoding(const std::string& rSource, int sourceCodePage,
360        std::string& rDest, int destCodePage)
361{
362        WCHAR* pWide = ConvertToWideString(rSource.c_str(), sourceCodePage,
363                true);
364        if (pWide == NULL)
365        {
366                ::syslog(LOG_ERR, "Failed to convert string '%s' from "
367                        "current code page %d to wide string: %s",
368                        rSource.c_str(), sourceCodePage,
369                        GetErrorMessage(GetLastError()).c_str());
370                return false;
371        }
372
373        char* pConsole = ConvertFromWideString(pWide, destCodePage);
374        delete [] pWide;
375
376        if (!pConsole)
377        {
378                // Error should have been logged by ConvertFromWideString
379                return false;
380        }
381
382        rDest = pConsole;
383        delete [] pConsole;
384
385        return true;
386}
387
388bool ConvertToUtf8(const std::string& rSource, std::string& rDest,
389        int sourceCodePage)
390{
391        return ConvertEncoding(rSource, sourceCodePage, rDest, CP_UTF8);
392}
393
394bool ConvertFromUtf8(const std::string& rSource, std::string& rDest,
395        int destCodePage)
396{
397        return ConvertEncoding(rSource, CP_UTF8, rDest, destCodePage);
398}
399
400bool ConvertConsoleToUtf8(const std::string& rSource, std::string& rDest)
401{
402        return ConvertToUtf8(rSource, rDest, GetConsoleCP());
403}
404
405bool ConvertUtf8ToConsole(const std::string& rSource, std::string& rDest)
406{
407        return ConvertFromUtf8(rSource, rDest, GetConsoleOutputCP());
408}
409
410// --------------------------------------------------------------------------
411//
412// Function
413//              Name:    ConvertPathToAbsoluteUnicode
414//              Purpose: Converts relative paths to absolute (with unicode marker)
415//              Created: 4th February 2006
416//
417// --------------------------------------------------------------------------
418std::string ConvertPathToAbsoluteUnicode(const char *pFileName)
419{
420        std::string filename;
421        for (int i = 0; pFileName[i] != 0; i++)
422        {
423                if (pFileName[i] == '/')
424                {
425                        filename += '\\';
426                }
427                else
428                {
429                        filename += pFileName[i];
430                }
431        }
432
433        std::string tmpStr("\\\\?\\");
434       
435        // Is the path relative or absolute?
436        // Absolute paths on Windows are always a drive letter
437        // followed by ':'
438               
439        char wd[PATH_MAX];
440        if (::getcwd(wd, PATH_MAX) == 0)
441        {
442                ::syslog(LOG_WARNING, 
443                        "Failed to open '%s': path too long", 
444                        pFileName);
445                errno = ENAMETOOLONG;
446                winerrno = ERROR_INVALID_NAME;
447                tmpStr = "";
448                return tmpStr;
449        }
450
451        if (filename.length() > 4 && filename[0] == '\\' &&
452                filename[1] == '\\' && filename[2] == '?' &&
453                filename[3] == '\\')
454        {
455                // File is already in absolute utf-8 format, e.g.
456                // \\?\GLOBALROOT\...
457                tmpStr = "";
458        }
459        else if (filename.length() > 2 && filename[0] == '\\' &&
460                filename[1] == '\\')
461        {
462                tmpStr += "UNC\\";
463                filename.replace(0, 2, "");
464                // \\?\UNC\<server>\<share>
465                // see http://msdn2.microsoft.com/en-us/library/aa365247.aspx
466        }
467        else if (filename.length() >= 1 && filename[0] == '\\')
468        {
469                // starts with \, i.e. root directory of current drive.
470                tmpStr = wd;
471                tmpStr.resize(2); // drive letter and colon
472        }
473        else if (filename.length() >= 2 && filename[1] != ':')
474        {
475                // Must be a relative path. We need to get the
476                // current directory to make it absolute.
477                tmpStr += wd;
478                if (tmpStr[tmpStr.length()-1] != '\\')
479                {
480                        tmpStr += '\\';
481                }
482        }
483       
484        tmpStr += filename;
485
486        // We are using direct filename access, which does not support ..,
487        // so we need to implement it ourselves.
488
489        for (std::string::size_type i = 1; i < tmpStr.size() - 3; i++)
490        {
491                if (tmpStr.substr(i, 3) == "\\..")
492                {
493                        std::string::size_type lastSlash =
494                                tmpStr.rfind('\\', i - 1);
495
496                        if (lastSlash == std::string::npos)
497                        {
498                                // no previous directory, ignore it,
499                                // CreateFile will fail with error 123
500                        }
501                        else
502                        {
503                                tmpStr.replace(lastSlash, i + 3 - lastSlash,
504                                        "");
505                        }
506
507                        i = lastSlash - 1;
508                }
509        }
510
511        return tmpStr;
512}
513
514std::string GetErrorMessage(DWORD errorCode)
515{
516        char* pMsgBuf = NULL;
517       
518        DWORD chars = FormatMessage
519        (
520                FORMAT_MESSAGE_ALLOCATE_BUFFER | 
521                FORMAT_MESSAGE_FROM_SYSTEM,
522                NULL,
523                errorCode,
524                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
525                (char *)(&pMsgBuf),
526                0, NULL
527        );
528
529        if (chars == 0 || pMsgBuf == NULL)
530        {
531                return std::string("failed to get error message");
532        }
533
534        // remove embedded newline
535        pMsgBuf[chars - 1] = 0;
536        pMsgBuf[chars - 2] = 0;
537
538        std::ostringstream line;
539        line << pMsgBuf << " (" << errorCode << ")";
540        LocalFree(pMsgBuf);
541
542        return line.str();
543}
544
545// --------------------------------------------------------------------------
546//
547// Function
548//              Name:    openfile
549//              Purpose: replacement for any open calls - handles unicode
550//                      filenames - supplied in utf8
551//              Created: 25th October 2004
552//
553// --------------------------------------------------------------------------
554HANDLE openfile(const char *pFileName, int flags, int mode)
555{
556        winerrno = ERROR_INVALID_FUNCTION;
557
558        std::string AbsPathWithUnicode = 
559                ConvertPathToAbsoluteUnicode(pFileName);
560       
561        if (AbsPathWithUnicode.size() == 0)
562        {
563                // error already logged by ConvertPathToAbsoluteUnicode()
564                return INVALID_HANDLE_VALUE;
565        }
566       
567        WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
568        // We are responsible for freeing pBuffer
569       
570        if (pBuffer == NULL)
571        {
572                // error already logged by ConvertUtf8ToWideString()
573                return INVALID_HANDLE_VALUE;
574        }
575
576        // flags could be O_WRONLY | O_CREAT | O_RDONLY
577        DWORD createDisposition = OPEN_EXISTING;
578        DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE
579                | FILE_SHARE_DELETE;
580        DWORD accessRights = FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY
581                | FILE_READ_EA;
582
583        if (flags & O_WRONLY)
584        {
585                accessRights = FILE_WRITE_DATA;
586        }
587        else if (flags & O_RDWR)
588        {
589                accessRights |= FILE_WRITE_ATTRIBUTES
590                        | FILE_WRITE_DATA | FILE_WRITE_EA;
591        }
592
593        if (flags & O_CREAT)
594        {
595                createDisposition = OPEN_ALWAYS;
596        }
597
598        if (flags & O_TRUNC)
599        {
600                createDisposition = CREATE_ALWAYS;
601        }
602
603        if ((flags & O_CREAT) && (flags & O_EXCL))
604        {
605                createDisposition = CREATE_NEW;
606        }
607
608        if (flags & O_LOCK)
609        {
610                shareMode = 0;
611        }
612
613        DWORD winFlags = FILE_FLAG_BACKUP_SEMANTICS;
614        if (flags & O_TEMPORARY)
615        {
616                winFlags  |= FILE_FLAG_DELETE_ON_CLOSE;
617        }
618
619        HANDLE hdir = CreateFileW(pBuffer, 
620                accessRights, 
621                shareMode, 
622                NULL, 
623                createDisposition, 
624                winFlags,
625                NULL);
626       
627        delete [] pBuffer;
628
629        if (hdir == INVALID_HANDLE_VALUE)
630        {
631                winerrno = GetLastError();
632                switch(winerrno)
633                {
634                        case ERROR_SHARING_VIOLATION:
635                        errno = EBUSY;
636                        break;
637
638                        default:
639                        errno = EINVAL;
640                }
641
642                ::syslog(LOG_WARNING, "Failed to open file '%s': "
643                        "%s", pFileName, 
644                        GetErrorMessage(GetLastError()).c_str());
645
646                return INVALID_HANDLE_VALUE;
647        }
648
649        if (flags & O_APPEND)
650        {
651                if (SetFilePointer(hdir, 0, NULL, FILE_END) ==
652                        INVALID_SET_FILE_POINTER)
653                {
654                        winerrno = GetLastError();
655                        errno = EINVAL;
656                        CloseHandle(hdir);
657                        return INVALID_HANDLE_VALUE;
658                }
659        }
660
661        winerrno = NO_ERROR;
662        return hdir;
663}
664
665// --------------------------------------------------------------------------
666//
667// Function
668//              Name:    emu_fstat
669//              Purpose: replacement for fstat. Supply a windows handle.
670//                       Returns a struct emu_stat to have room for 64-bit
671//                       file identifier in st_ino (mingw allows only 16!)
672//              Created: 25th October 2004
673//
674// --------------------------------------------------------------------------
675int emu_fstat(HANDLE hdir, struct emu_stat * st)
676{
677        if (hdir == INVALID_HANDLE_VALUE)
678        {
679                ::syslog(LOG_ERR, "Error: invalid file handle in emu_fstat()");
680                errno = EBADF;
681                return -1;
682        }
683
684        BY_HANDLE_FILE_INFORMATION fi;
685        if (!GetFileInformationByHandle(hdir, &fi))
686        {
687                ::syslog(LOG_WARNING, "Failed to read file information: "
688                        "%s", GetErrorMessage(GetLastError()).c_str());
689                errno = EACCES;
690                return -1;
691        }
692
693        if (INVALID_FILE_ATTRIBUTES == fi.dwFileAttributes)
694        {
695                ::syslog(LOG_WARNING, "Failed to get file attributes: "
696                        "%s", GetErrorMessage(GetLastError()).c_str());
697                errno = EACCES;
698                return -1;
699        }
700
701        memset(st, 0, sizeof(*st));
702
703        // This is how we get our INODE (equivalent) information
704        ULARGE_INTEGER conv;
705        conv.HighPart = fi.nFileIndexHigh;
706        conv.LowPart  = fi.nFileIndexLow;
707        st->st_ino = conv.QuadPart;
708
709        // get the time information
710        st->st_ctime = ConvertFileTimeToTime_t(&fi.ftCreationTime);
711        st->st_atime = ConvertFileTimeToTime_t(&fi.ftLastAccessTime);
712        st->st_mtime = ConvertFileTimeToTime_t(&fi.ftLastWriteTime);
713
714        if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
715        {
716                st->st_size = 0;
717        }
718        else
719        {
720                conv.HighPart = fi.nFileSizeHigh;
721                conv.LowPart  = fi.nFileSizeLow;
722                st->st_size = conv.QuadPart;
723        }
724
725        // at the mo
726        st->st_uid = 0;
727        st->st_gid = 0;
728        st->st_nlink = 1;
729
730        // the mode of the file
731        // mode zero will make it impossible to restore on Unix
732        // (no access to anybody, including the owner).
733        // we'll fake a sensible mode:
734        // all objects get user read (0400)
735        // if it's a directory it gets user execute (0100)
736        // if it's not read-only it gets user write (0200)
737        st->st_mode = S_IREAD;
738
739        if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
740        {
741                st->st_mode |= S_IFDIR | S_IEXEC;
742        }
743        else
744        {
745                st->st_mode |= S_IFREG;
746        }
747
748        if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
749        {
750                st->st_mode |= S_IWRITE;
751        }
752
753        // st_dev is normally zero, regardless of the drive letter,
754        // since backup locations can't normally span drives. However,
755        // a reparse point does allow all kinds of weird stuff to happen.
756        // We set st_dev to 1 for a reparse point, so that Box will detect
757        // a change of device number (from 0) and refuse to recurse down
758        // the reparse point (which could lead to havoc).
759
760        if (fi.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
761        {
762                st->st_dev = 1;
763        }
764        else
765        {
766                st->st_dev = 0;
767        }
768
769        return 0;
770}
771
772// --------------------------------------------------------------------------
773//
774// Function
775//              Name:    OpenFileByNameUtf8
776//              Purpose: Converts filename to Unicode and returns
777//                      a handle to it. In case of error, sets errno,
778//                      logs the error and returns NULL.
779//              Created: 10th December 2004
780//
781// --------------------------------------------------------------------------
782HANDLE OpenFileByNameUtf8(const char* pFileName, DWORD flags)
783{
784        std::string AbsPathWithUnicode = 
785                ConvertPathToAbsoluteUnicode(pFileName);
786       
787        if (AbsPathWithUnicode.size() == 0)
788        {
789                // error already logged by ConvertPathToAbsoluteUnicode()
790                return NULL;
791        }
792       
793        WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
794        // We are responsible for freeing pBuffer
795       
796        if (pBuffer == NULL)
797        {
798                // error already logged by ConvertUtf8ToWideString()
799                return NULL;
800        }
801
802        HANDLE handle = CreateFileW(pBuffer, 
803                flags,
804                FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, 
805                NULL, 
806                OPEN_EXISTING, 
807                FILE_FLAG_BACKUP_SEMANTICS,
808                NULL);
809
810        if (handle == INVALID_HANDLE_VALUE)
811        {
812                // if our open fails we should always be able to
813                // open in this mode - to get the inode information
814                // at least one process must have the file open -
815                // in this case someone else does.
816                handle = CreateFileW(pBuffer, 
817                        READ_CONTROL,
818                        FILE_SHARE_READ, 
819                        NULL, 
820                        OPEN_EXISTING, 
821                        FILE_FLAG_BACKUP_SEMANTICS,
822                        NULL);
823        }
824
825        delete [] pBuffer;
826
827        if (handle == INVALID_HANDLE_VALUE)
828        {
829                DWORD err = GetLastError();
830
831                if (err == ERROR_FILE_NOT_FOUND ||
832                        err == ERROR_PATH_NOT_FOUND)
833                {
834                        errno = ENOENT;
835                }
836                else
837                {
838                        ::syslog(LOG_WARNING, "Failed to open '%s': "
839                                "%s", pFileName, 
840                                GetErrorMessage(err).c_str());
841                        errno = EACCES;
842                }
843
844                return NULL;
845        }
846
847        return handle;
848}
849
850// --------------------------------------------------------------------------
851//
852// Function
853//              Name:    emu_stat
854//              Purpose: replacement for the lstat and stat functions.
855//                       Works with unicode filenames supplied in utf8.
856//                       Returns a struct emu_stat to have room for 64-bit
857//                       file identifier in st_ino (mingw allows only 16!)
858//              Created: 25th October 2004
859//
860// --------------------------------------------------------------------------
861int emu_stat(const char * pName, struct emu_stat * st)
862{
863        HANDLE handle = OpenFileByNameUtf8(pName, 
864                FILE_READ_ATTRIBUTES | FILE_READ_EA);
865
866        if (handle == NULL)
867        {
868                // errno already set and error logged by OpenFileByNameUtf8()
869                return -1;
870        }
871
872        int retVal = emu_fstat(handle, st);
873        if (retVal != 0)
874        {
875                // error logged, but without filename
876                ::syslog(LOG_WARNING, "Failed to get file information "
877                        "for '%s'", pName);
878        }
879
880        // close the handle
881        CloseHandle(handle);
882
883        return retVal;
884}
885
886// --------------------------------------------------------------------------
887//
888// Function
889//              Name:    statfs
890//              Purpose: returns the mount point of where a file is located -
891//                      in this case the volume serial number
892//              Created: 25th October 2004
893//
894// --------------------------------------------------------------------------
895int statfs(const char * pName, struct statfs * s)
896{
897        HANDLE handle = OpenFileByNameUtf8(pName,
898                FILE_READ_ATTRIBUTES | FILE_READ_EA);
899
900        if (handle == NULL)
901        {
902                // errno already set and error logged by OpenFileByNameUtf8()
903                return -1;
904        }
905
906        BY_HANDLE_FILE_INFORMATION fi;
907        if (!GetFileInformationByHandle(handle, &fi))
908        {
909                ::syslog(LOG_WARNING, "Failed to get file information "
910                        "for '%s': %s", pName,
911                        GetErrorMessage(GetLastError()).c_str());
912                CloseHandle(handle);
913                errno = EACCES;
914                return -1;
915        }
916
917        // convert volume serial number to a string
918        _ui64toa(fi.dwVolumeSerialNumber, s->f_mntonname + 1, 16);
919
920        // pseudo unix mount point
921        s->f_mntonname[0] = '\\';
922
923        CloseHandle(handle);   // close the handle
924
925        return 0;
926}
927
928// --------------------------------------------------------------------------
929//
930// Function
931//              Name:    emu_utimes
932//              Purpose: replacement for the POSIX utimes() function,
933//                      works with unicode filenames supplied in utf8 format,
934//                      sets creation time instead of last access time.
935//              Created: 25th July 2006
936//
937// --------------------------------------------------------------------------
938int emu_utimes(const char * pName, const struct timeval times[])
939{
940        FILETIME creationTime;
941        if (!ConvertTime_tToFileTime(times[0].tv_sec, &creationTime))
942        {
943                errno = EINVAL;
944                return -1;
945        }
946
947        FILETIME modificationTime;
948        if (!ConvertTime_tToFileTime(times[1].tv_sec, &modificationTime))
949        {
950                errno = EINVAL;
951                return -1;
952        }
953
954        HANDLE handle = OpenFileByNameUtf8(pName, FILE_WRITE_ATTRIBUTES);
955
956        if (handle == NULL)
957        {
958                // errno already set and error logged by OpenFileByNameUtf8()
959                return -1;
960        }
961
962        if (!SetFileTime(handle, &creationTime, NULL, &modificationTime))
963        {
964                ::syslog(LOG_ERR, "Failed to set times on '%s': %s", pName,
965                        GetErrorMessage(GetLastError()).c_str());
966                CloseHandle(handle);
967                return 1;
968        }
969
970        CloseHandle(handle);
971        return 0;
972}
973
974// --------------------------------------------------------------------------
975//
976// Function
977//              Name:    emu_chmod
978//              Purpose: replacement for the POSIX chmod function,
979//                      works with unicode filenames supplied in utf8 format
980//              Created: 26th July 2006
981//
982// --------------------------------------------------------------------------
983int emu_chmod(const char * pName, mode_t mode)
984{
985        std::string AbsPathWithUnicode = 
986                ConvertPathToAbsoluteUnicode(pName);
987       
988        if (AbsPathWithUnicode.size() == 0)
989        {
990                // error already logged by ConvertPathToAbsoluteUnicode()
991                return -1;
992        }
993       
994        WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
995        // We are responsible for freeing pBuffer
996       
997        if (pBuffer == NULL)
998        {
999                // error already logged by ConvertUtf8ToWideString()
1000                free(pBuffer);
1001                return -1;
1002        }
1003
1004        DWORD attribs = GetFileAttributesW(pBuffer);
1005        if (attribs == INVALID_FILE_ATTRIBUTES)
1006        {
1007                ::syslog(LOG_ERR, "Failed to get file attributes of '%s': %s",
1008                        pName, GetErrorMessage(GetLastError()).c_str());
1009                errno = EACCES;
1010                free(pBuffer);
1011                return -1;
1012        }
1013
1014        if (mode & S_IWRITE)
1015        {
1016                attribs &= ~FILE_ATTRIBUTE_READONLY;
1017        }
1018        else
1019        {
1020                attribs |= FILE_ATTRIBUTE_READONLY;
1021        }
1022
1023        if (!SetFileAttributesW(pBuffer, attribs))
1024        {
1025                ::syslog(LOG_ERR, "Failed to set file attributes of '%s': %s",
1026                        pName, GetErrorMessage(GetLastError()).c_str());
1027                errno = EACCES;
1028                free(pBuffer);
1029                return -1;
1030        }
1031
1032        delete [] pBuffer;
1033        return 0;
1034}
1035
1036
1037// --------------------------------------------------------------------------
1038//
1039// Function
1040//              Name:    opendir
1041//              Purpose: replacement for unix function, uses win32 findfirst routines
1042//              Created: 25th October 2004
1043//
1044// --------------------------------------------------------------------------
1045DIR *opendir(const char *name)
1046{
1047        if (!name || !name[0])
1048        {
1049                errno = EINVAL;
1050                return NULL;
1051        }
1052       
1053        std::string dirName(name);
1054
1055        //append a '\' win32 findfirst is sensitive to this
1056        if (dirName[dirName.size()-1] != '\\' || dirName[dirName.size()-1] != '/')
1057        {
1058                dirName += '\\';
1059        }
1060
1061        // what is the search string? - everything
1062        dirName += '*';
1063
1064        DIR *pDir = new DIR;
1065        if (pDir == NULL)
1066        {
1067                errno = ENOMEM;
1068                return NULL;
1069        }
1070
1071        pDir->name = ConvertUtf8ToWideString(dirName.c_str());
1072        // We are responsible for freeing dir->name with delete[]
1073       
1074        if (pDir->name == NULL)
1075        {
1076                delete pDir;
1077                return NULL;
1078        }
1079
1080        pDir->fd = FindFirstFileW(pDir->name, &pDir->info);
1081        DWORD tmp = GetLastError();
1082
1083        if (pDir->fd == INVALID_HANDLE_VALUE)
1084        {
1085                delete [] pDir->name;
1086                delete pDir;
1087                return NULL;
1088        }
1089       
1090        pDir->result.d_name = 0;
1091        return pDir;
1092}
1093
1094// this kinda makes it not thread friendly!
1095// but I don't think it needs to be.
1096char tempbuff[MAX_PATH];
1097
1098// --------------------------------------------------------------------------
1099//
1100// Function
1101//              Name:    readdir
1102//              Purpose: as function above
1103//              Created: 25th October 2004
1104//
1105// --------------------------------------------------------------------------
1106struct dirent *readdir(DIR *dp)
1107{
1108        try
1109        {
1110                struct dirent *den = NULL;
1111
1112                if (dp && dp->fd != INVALID_HANDLE_VALUE)
1113                {
1114                        // first time around, when dp->result.d_name == NULL, use
1115                        // the values returned by FindFirstFile. After that, call
1116                        // FindNextFileW to return new ones.
1117                        if (!dp->result.d_name ||
1118                                FindNextFileW(dp->fd, &dp->info) != 0)
1119                        {
1120                                den = &dp->result;
1121                                std::wstring input(dp->info.cFileName);
1122                                memset(tempbuff, 0, sizeof(tempbuff));
1123                                WideCharToMultiByte(CP_UTF8, 0, dp->info.cFileName, 
1124                                        -1, &tempbuff[0], sizeof (tempbuff), 
1125                                        NULL, NULL);
1126                                //den->d_name = (char *)dp->info.name;
1127                                den->d_name = &tempbuff[0];
1128                                den->d_type = dp->info.dwFileAttributes;
1129                        }
1130                        else // FindNextFileW failed
1131                        {
1132                                // Why did it fail? No more files?
1133                                winerrno = GetLastError();
1134                                den = NULL;
1135
1136                                if (winerrno == ERROR_NO_MORE_FILES)
1137                                {
1138                                        errno = 0; // no more files
1139                                }
1140                                else
1141                                {
1142                                        errno = ENOSYS;
1143                                }
1144                        }
1145                }
1146                else
1147                {
1148                        errno = EBADF;
1149                }
1150
1151                return den;
1152        }
1153        catch (...)
1154        {
1155                printf("Caught readdir");
1156        }
1157        return NULL;
1158}
1159
1160// --------------------------------------------------------------------------
1161//
1162// Function
1163//              Name:    closedir
1164//              Purpose: as function above
1165//              Created: 25th October 2004
1166//
1167// --------------------------------------------------------------------------
1168int closedir(DIR *dp)
1169{
1170        try
1171        {
1172                BOOL finres = false;
1173
1174                if (dp)
1175                {
1176                        if(dp->fd != INVALID_HANDLE_VALUE)
1177                        {
1178                                finres = FindClose(dp->fd);
1179                        }
1180
1181                        delete [] dp->name;
1182                        delete dp;
1183                }
1184
1185                if (finres == FALSE) // errors go to EBADF
1186                {
1187                        winerrno = GetLastError();
1188                        errno = EBADF;
1189                }
1190
1191                return (finres == TRUE) ? 0 : -1;
1192        }
1193        catch (...)
1194        {
1195                printf("Caught closedir");
1196        }
1197        return -1;
1198}
1199
1200// --------------------------------------------------------------------------
1201//
1202// Function
1203//              Name:    poll
1204//              Purpose: a weak implimentation (just enough for box)
1205//                      of the unix poll for winsock2
1206//              Created: 25th October 2004
1207//
1208// --------------------------------------------------------------------------
1209int poll (struct pollfd *ufds, unsigned long nfds, int timeout)
1210{
1211        try
1212        {
1213                fd_set readfd;
1214                fd_set writefd;
1215
1216                FD_ZERO(&readfd);
1217                FD_ZERO(&writefd);
1218
1219                // struct pollfd *ufdsTmp = ufds;
1220
1221                timeval timOut;
1222                timeval *tmpptr; 
1223
1224                if (timeout == INFTIM)
1225                        tmpptr = NULL;
1226                else
1227                        tmpptr = &timOut;
1228
1229                timOut.tv_sec  = timeout / 1000;
1230                timOut.tv_usec = timeout * 1000;
1231
1232                for (unsigned long i = 0; i < nfds; i++)
1233                {
1234                        struct pollfd* ufd = &(ufds[i]);
1235
1236                        if (ufd->events & POLLIN)
1237                        {
1238                                FD_SET(ufd->fd, &readfd);
1239                        }
1240
1241                        if (ufd->events & POLLOUT)
1242                        {
1243                                FD_SET(ufd->fd, &writefd);
1244                        }
1245
1246                        if (ufd->events & ~(POLLIN | POLLOUT))
1247                        {
1248                                printf("Unsupported poll bits %d",
1249                                        ufd->events);
1250                                return -1;
1251                        }
1252                }       
1253
1254                int nready = select(0, &readfd, &writefd, 0, tmpptr);
1255
1256                if (nready == SOCKET_ERROR)
1257                {
1258                        // int errval = WSAGetLastError();
1259
1260                        struct pollfd* pufd = ufds;
1261                        for (unsigned long i = 0; i < nfds; i++)
1262                        {
1263                                pufd->revents = POLLERR;
1264                                pufd++;
1265                        }
1266                        return (-1);
1267                }
1268                else if (nready > 0)
1269                {
1270                        for (unsigned long i = 0; i < nfds; i++)
1271                        {
1272                                struct pollfd *ufd = &(ufds[i]);
1273
1274                                if (FD_ISSET(ufd->fd, &readfd))
1275                                {
1276                                        ufd->revents |= POLLIN;
1277                                }
1278
1279                                if (FD_ISSET(ufd->fd, &writefd))
1280                                {
1281                                        ufd->revents |= POLLOUT;
1282                                }
1283                        }
1284                }
1285
1286                return nready;
1287        }
1288        catch (...)
1289        {
1290                printf("Caught poll");
1291        }
1292
1293        return -1;
1294}
1295
1296// copied from MSDN: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/eventlog/base/adding_a_source_to_the_registry.asp
1297
1298BOOL AddEventSource
1299(
1300        LPTSTR pszSrcName, // event source name
1301        DWORD  dwNum       // number of categories
1302)
1303{
1304        // Work out the executable file name, to register ourselves
1305        // as the event source
1306
1307        WCHAR cmd[MAX_PATH];
1308        DWORD len = GetModuleFileNameW(NULL, cmd, MAX_PATH);
1309
1310        if (len == 0)
1311        {
1312                ::syslog(LOG_ERR, "Failed to get the program file name: %s",
1313                        GetErrorMessage(GetLastError()).c_str());
1314                return FALSE;
1315        }
1316
1317        // Create the event source as a subkey of the log.
1318
1319        std::string regkey("SYSTEM\\CurrentControlSet\\Services\\EventLog\\"
1320                "Application\\");
1321        regkey += pszSrcName; 
1322 
1323        HKEY hk;
1324        DWORD dwDisp;
1325
1326        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, regkey.c_str(), 
1327                         0, NULL, REG_OPTION_NON_VOLATILE,
1328                         KEY_WRITE, NULL, &hk, &dwDisp)) 
1329        {
1330                ::syslog(LOG_ERR, "Failed to create the registry key: %s",
1331                        GetErrorMessage(GetLastError()).c_str());
1332                return FALSE;
1333        }
1334
1335        // Set the name of the message file.
1336 
1337        if (RegSetValueExW(hk,                 // subkey handle
1338                           L"EventMessageFile", // value name
1339                           0,                  // must be zero
1340                           REG_EXPAND_SZ,      // value type
1341                           (LPBYTE)cmd,        // pointer to value data
1342                           len*sizeof(WCHAR))) // data size
1343        {
1344                ::syslog(LOG_ERR, "Failed to set the event message file: %s",
1345                        GetErrorMessage(GetLastError()).c_str());
1346                RegCloseKey(hk); 
1347                return FALSE;
1348        }
1349 
1350        // Set the supported event types.
1351 
1352        DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | 
1353                  EVENTLOG_INFORMATION_TYPE; 
1354 
1355        if (RegSetValueEx(hk,               // subkey handle
1356                          "TypesSupported", // value name
1357                          0,                // must be zero
1358                          REG_DWORD,        // value type
1359                          (LPBYTE) &dwData, // pointer to value data
1360                          sizeof(DWORD)))   // length of value data
1361        {
1362                ::syslog(LOG_ERR, "Failed to set the supported types: %s",
1363                        GetErrorMessage(GetLastError()).c_str());
1364                RegCloseKey(hk); 
1365                return FALSE;
1366        }
1367 
1368        // Set the category message file and number of categories.
1369
1370        if (RegSetValueExW(hk,                    // subkey handle
1371                           L"CategoryMessageFile", // value name
1372                           0,                     // must be zero
1373                           REG_EXPAND_SZ,         // value type
1374                           (LPBYTE)cmd,           // pointer to value data
1375                           len*sizeof(WCHAR)))    // data size
1376        {
1377                ::syslog(LOG_ERR, "Failed to set the category message file: "
1378                        "%s", GetErrorMessage(GetLastError()).c_str());
1379                RegCloseKey(hk); 
1380                return FALSE;
1381        }
1382 
1383        if (RegSetValueEx(hk,              // subkey handle
1384                          "CategoryCount", // value name
1385                          0,               // must be zero
1386                          REG_DWORD,       // value type
1387                          (LPBYTE) &dwNum, // pointer to value data
1388                          sizeof(DWORD)))  // length of value data
1389        {
1390                ::syslog(LOG_ERR, "Failed to set the category count: %s",
1391                        GetErrorMessage(GetLastError()).c_str());
1392                RegCloseKey(hk); 
1393                return FALSE;
1394        }
1395
1396        RegCloseKey(hk); 
1397        return TRUE;
1398}
1399
1400static HANDLE gSyslogH = 0;
1401static bool sHaveWarnedEventLogFull = false;
1402
1403void openlog(const char * daemonName, int, int)
1404{
1405        std::string nameStr = "Box Backup (";
1406        nameStr += daemonName;
1407        nameStr += ")";
1408
1409        // register a default event source, so that we can
1410        // log errors with the process of adding or registering our own.
1411        gSyslogH = RegisterEventSource(
1412                NULL,        // uses local computer
1413                nameStr.c_str()); // source name
1414        if (gSyslogH == NULL) 
1415        {
1416        }
1417
1418        char* name = strdup(nameStr.c_str());
1419        BOOL success = AddEventSource(name, 0);
1420        free(name);
1421
1422        if (!success)
1423        {
1424                ::syslog(LOG_ERR, "Failed to add our own event source");
1425                return;
1426        }
1427
1428        HANDLE newSyslogH = RegisterEventSource(NULL, nameStr.c_str());
1429        if (newSyslogH == NULL)
1430        {
1431                ::syslog(LOG_ERR, "Failed to register our own event source: "
1432                        "%s", GetErrorMessage(GetLastError()).c_str());
1433                return;
1434        }
1435
1436        DeregisterEventSource(gSyslogH);
1437        gSyslogH = newSyslogH;
1438}
1439
1440void closelog(void)
1441{
1442        DeregisterEventSource(gSyslogH); 
1443}
1444
1445void syslog(int loglevel, const char *frmt, ...)
1446{
1447        WORD errinfo;
1448        char buffer[4096];
1449        std::string sixfour(frmt);
1450
1451        switch (loglevel)
1452        {
1453        case LOG_INFO:
1454                errinfo = EVENTLOG_INFORMATION_TYPE;
1455                break;
1456        case LOG_ERR:
1457                errinfo = EVENTLOG_ERROR_TYPE;
1458                break;
1459        case LOG_WARNING:
1460                errinfo = EVENTLOG_WARNING_TYPE;
1461                break;
1462        default:
1463                errinfo = EVENTLOG_WARNING_TYPE;
1464                break;
1465        }
1466
1467        // taken from MSDN
1468        int sixfourpos;
1469        while ( (sixfourpos = (int)sixfour.find("%ll")) != -1 )
1470        {
1471                // maintain portability - change the 64 bit formater...
1472                std::string temp = sixfour.substr(0,sixfourpos);
1473                temp += "%I64";
1474                temp += sixfour.substr(sixfourpos+3, sixfour.length());
1475                sixfour = temp;
1476        }
1477
1478        // printf("parsed string is:%s\r\n", sixfour.c_str());
1479
1480        va_list args;
1481        va_start(args, frmt);
1482
1483        int len = vsnprintf(buffer, sizeof(buffer)-1, sixfour.c_str(), args);
1484        assert(len >= 0);
1485        if (len < 0) 
1486        {
1487                printf("%s\r\n", buffer);
1488                fflush(stdout);
1489                return;
1490        }
1491       
1492        assert((size_t)len < sizeof(buffer));
1493        buffer[sizeof(buffer)-1] = 0;
1494
1495        va_end(args);
1496
1497        if (gSyslogH == 0)
1498        {
1499                printf("%s\r\n", buffer);
1500                fflush(stdout);
1501                return;
1502        }
1503
1504        WCHAR* pWide = ConvertToWideString(buffer, CP_UTF8, false);
1505        // must delete[] pWide
1506
1507        DWORD result;
1508
1509        if (pWide == NULL)
1510        {
1511                std::string buffer2 = buffer;
1512                buffer2 += " (failed to convert string encoding)";
1513                LPCSTR strings[] = { buffer2.c_str(), NULL };
1514
1515                result = ReportEventA(gSyslogH, // event log handle
1516                        errinfo,               // event type
1517                        0,                     // category zero
1518                        MSG_ERR,               // event identifier -
1519                                               // we will call them all the same
1520                        NULL,                  // no user security identifier
1521                        1,                     // one substitution string
1522                        0,                     // no data
1523                        strings,               // pointer to string array
1524                        NULL);                 // pointer to data
1525        }
1526        else
1527        {
1528                LPCWSTR strings[] = { pWide, NULL };
1529                result = ReportEventW(gSyslogH, // event log handle
1530                        errinfo,               // event type
1531                        0,                     // category zero
1532                        MSG_ERR,               // event identifier -
1533                                               // we will call them all the same
1534                        NULL,                  // no user security identifier
1535                        1,                     // one substitution string
1536                        0,                     // no data
1537                        strings,               // pointer to string array
1538                        NULL);                 // pointer to data
1539                delete [] pWide;
1540        }
1541               
1542        if (result == 0)
1543        {
1544                DWORD err = GetLastError();
1545                if (err == ERROR_LOG_FILE_FULL)
1546                {
1547                        if (!sHaveWarnedEventLogFull)
1548                        {
1549                                printf("Unable to send message to Event Log "
1550                                        "(Event Log is full):\r\n");
1551                                fflush(stdout);
1552                                sHaveWarnedEventLogFull = TRUE;
1553                        }
1554                }
1555                else
1556                {
1557                        printf("Unable to send message to Event Log: %s:\r\n",
1558                                GetErrorMessage(err).c_str());
1559                        fflush(stdout);
1560                }
1561        }
1562        else
1563        {
1564                sHaveWarnedEventLogFull = false;
1565        }
1566}
1567
1568int emu_chdir(const char* pDirName)
1569{
1570        /*
1571        std::string AbsPathWithUnicode =
1572                ConvertPathToAbsoluteUnicode(pDirName);
1573
1574        if (AbsPathWithUnicode.size() == 0)
1575        {
1576                // error already logged by ConvertPathToAbsoluteUnicode()
1577                return -1;
1578        }
1579
1580        WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
1581        */
1582
1583        WCHAR* pBuffer = ConvertUtf8ToWideString(pDirName);
1584        if (!pBuffer) return -1;
1585
1586        int result = SetCurrentDirectoryW(pBuffer);
1587        delete [] pBuffer;
1588
1589        if (result != 0) return 0;
1590
1591        errno = EACCES;
1592        fprintf(stderr, "Failed to change directory to '%s': %s\n",
1593                pDirName, GetErrorMessage(GetLastError()).c_str());
1594        return -1;
1595}
1596
1597char* emu_getcwd(char* pBuffer, int BufSize)
1598{
1599        DWORD len = GetCurrentDirectoryW(0, NULL);
1600        if (len == 0)
1601        {
1602                errno = EINVAL;
1603                return NULL;
1604        }
1605
1606        if ((int)len > BufSize)
1607        {
1608                errno = ENAMETOOLONG;
1609                return NULL;
1610        }
1611
1612        WCHAR* pWide = new WCHAR [len];
1613        if (!pWide)
1614        {
1615                errno = ENOMEM;
1616                return NULL;
1617        }
1618
1619        DWORD result = GetCurrentDirectoryW(len, pWide);
1620        if (result <= 0 || result >= len)
1621        {
1622                errno = EACCES;
1623                delete [] pWide;
1624                return NULL;
1625        }
1626
1627        char* pUtf8 = ConvertFromWideString(pWide, CP_UTF8);
1628        delete [] pWide;
1629
1630        if (!pUtf8)
1631        {
1632                return NULL;
1633        }
1634
1635        strncpy(pBuffer, pUtf8, BufSize - 1);
1636        pBuffer[BufSize - 1] = 0;
1637        delete [] pUtf8;
1638
1639        return pBuffer;
1640}
1641
1642int emu_mkdir(const char* pPathName)
1643{
1644        std::string AbsPathWithUnicode = 
1645                ConvertPathToAbsoluteUnicode(pPathName);
1646
1647        if (AbsPathWithUnicode.size() == 0)
1648        {
1649                // error already logged by ConvertPathToAbsoluteUnicode()
1650                return -1;
1651        }
1652
1653        WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
1654        if (!pBuffer)
1655        {
1656                return -1;
1657        }
1658
1659        BOOL result = CreateDirectoryW(pBuffer, NULL);
1660        delete [] pBuffer;
1661
1662        if (!result)
1663        {
1664                errno = EACCES;
1665                return -1;
1666        }
1667
1668        return 0;
1669}
1670
1671int emu_unlink(const char* pFileName)
1672{
1673        std::string AbsPathWithUnicode = 
1674                ConvertPathToAbsoluteUnicode(pFileName);
1675
1676        if (AbsPathWithUnicode.size() == 0)
1677        {
1678                // error already logged by ConvertPathToAbsoluteUnicode()
1679                return -1;
1680        }
1681
1682        WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
1683        if (!pBuffer)
1684        {
1685                return -1;
1686        }
1687
1688        BOOL result = DeleteFileW(pBuffer);
1689        DWORD err = GetLastError();
1690        delete [] pBuffer;
1691
1692        if (!result)
1693        {
1694                if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
1695                {
1696                        errno = ENOENT;
1697                }
1698                else if (err == ERROR_SHARING_VIOLATION)
1699                {
1700                        errno = EBUSY;
1701                }
1702                else if (err == ERROR_ACCESS_DENIED)
1703                {
1704                        errno = EACCES;
1705                }
1706                else
1707                {
1708                        ::syslog(LOG_WARNING, "Failed to delete file "
1709                                "'%s': %s", pFileName, 
1710                                GetErrorMessage(err).c_str());
1711                        errno = ENOSYS;
1712                }
1713                return -1;
1714        }
1715
1716        return 0;
1717}
1718
1719int emu_rename(const char* pOldFileName, const char* pNewFileName)
1720{
1721        std::string OldPathWithUnicode = 
1722                ConvertPathToAbsoluteUnicode(pOldFileName);
1723
1724        if (OldPathWithUnicode.size() == 0)
1725        {
1726                // error already logged by ConvertPathToAbsoluteUnicode()
1727                return -1;
1728        }
1729
1730        WCHAR* pOldBuffer = ConvertUtf8ToWideString(OldPathWithUnicode.c_str());
1731        if (!pOldBuffer)
1732        {
1733                return -1;
1734        }
1735
1736        std::string NewPathWithUnicode = 
1737                ConvertPathToAbsoluteUnicode(pNewFileName);
1738
1739        if (NewPathWithUnicode.size() == 0)
1740        {
1741                // error already logged by ConvertPathToAbsoluteUnicode()
1742                delete [] pOldBuffer;
1743                return -1;
1744        }
1745
1746        WCHAR* pNewBuffer = ConvertUtf8ToWideString(NewPathWithUnicode.c_str());
1747        if (!pNewBuffer)
1748        {
1749                delete [] pOldBuffer;
1750                return -1;
1751        }
1752
1753        BOOL result = MoveFileW(pOldBuffer, pNewBuffer);
1754        DWORD err = GetLastError();
1755        delete [] pOldBuffer;
1756        delete [] pNewBuffer;
1757
1758        if (!result)
1759        {
1760                if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
1761                {
1762                        errno = ENOENT;
1763                }
1764                else if (err == ERROR_SHARING_VIOLATION)
1765                {
1766                        errno = EBUSY;
1767                }
1768                else if (err == ERROR_ACCESS_DENIED)
1769                {
1770                        errno = EACCES;
1771                }
1772                else
1773                {
1774                        ::syslog(LOG_WARNING, "Failed to rename file "
1775                                "'%s' to '%s': %s", pOldFileName, pNewFileName,
1776                                GetErrorMessage(err).c_str());
1777                        errno = ENOSYS;
1778                }
1779                return -1;
1780        }
1781
1782        return 0;
1783}
1784
1785int console_read(char* pBuffer, size_t BufferSize)
1786{
1787        HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
1788
1789        if (hConsole == INVALID_HANDLE_VALUE)
1790        {
1791                ::fprintf(stderr, "Failed to get a handle on standard input: "
1792                        "%s", GetErrorMessage(GetLastError()).c_str());
1793                return -1;
1794        }
1795
1796        size_t WideSize = BufferSize / 5;
1797        WCHAR* pWideBuffer = new WCHAR [WideSize + 1];
1798
1799        if (!pWideBuffer)
1800        {
1801                ::perror("Failed to allocate wide character buffer");
1802                return -1;
1803        }
1804
1805        DWORD numCharsRead = 0;
1806
1807        if (!ReadConsoleW(
1808                        hConsole,
1809                        pWideBuffer,
1810                        WideSize, // will not be null terminated by ReadConsole
1811                        &numCharsRead,
1812                        NULL // reserved
1813                )) 
1814        {
1815                ::fprintf(stderr, "Failed to read from console: %s\n",
1816                        GetErrorMessage(GetLastError()).c_str());
1817                return -1;
1818        }
1819
1820        pWideBuffer[numCharsRead] = 0;
1821
1822        char* pUtf8 = ConvertFromWideString(pWideBuffer, GetConsoleCP());
1823        delete [] pWideBuffer;
1824
1825        strncpy(pBuffer, pUtf8, BufferSize);
1826        delete [] pUtf8;
1827
1828        return strlen(pBuffer);
1829}
1830
1831int readv (int filedes, const struct iovec *vector, size_t count)
1832{
1833        int bytes = 0;
1834       
1835        for (size_t i = 0; i < count; i++)
1836        {
1837                int result = read(filedes, vector[i].iov_base, 
1838                        vector[i].iov_len);
1839                if (result < 0)
1840                {
1841                        return result;
1842                }
1843                bytes += result;
1844        }
1845
1846        return bytes;
1847}
1848
1849int writev(int filedes, const struct iovec *vector, size_t count)
1850{
1851        int bytes = 0;
1852       
1853        for (size_t i = 0; i < count; i++)
1854        {
1855                int result = write(filedes, vector[i].iov_base, 
1856                        vector[i].iov_len);
1857                if (result < 0)
1858                {
1859                        return result;
1860                }
1861                bytes += result;
1862        }
1863
1864        return bytes;
1865}
1866
1867// need this for conversions
1868time_t ConvertFileTimeToTime_t(FILETIME *fileTime)
1869{
1870        SYSTEMTIME stUTC;
1871        struct tm timeinfo;
1872
1873        // Convert the last-write time to local time.
1874        FileTimeToSystemTime(fileTime, &stUTC);
1875
1876        memset(&timeinfo, 0, sizeof(timeinfo)); 
1877        timeinfo.tm_sec = stUTC.wSecond;
1878        timeinfo.tm_min = stUTC.wMinute;
1879        timeinfo.tm_hour = stUTC.wHour;
1880        timeinfo.tm_mday = stUTC.wDay;
1881        timeinfo.tm_wday = stUTC.wDayOfWeek;
1882        timeinfo.tm_mon = stUTC.wMonth - 1;
1883        // timeinfo.tm_yday = ...;
1884        timeinfo.tm_year = stUTC.wYear - 1900;
1885
1886        time_t retVal = mktime(&timeinfo) - _timezone;
1887        return retVal;
1888}
1889
1890bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo)
1891{
1892        time_t adjusted = from + _timezone;
1893        struct tm *time_breakdown = gmtime(&adjusted);
1894        if (time_breakdown == NULL)
1895        {
1896                ::syslog(LOG_ERR, "Error: failed to convert time format: "
1897                        "%d is not a valid time\n", adjusted);
1898                return false;
1899        }
1900
1901        SYSTEMTIME stUTC;
1902        stUTC.wSecond       = time_breakdown->tm_sec;
1903        stUTC.wMinute       = time_breakdown->tm_min;
1904        stUTC.wHour         = time_breakdown->tm_hour;
1905        stUTC.wDay          = time_breakdown->tm_mday;
1906        stUTC.wDayOfWeek    = time_breakdown->tm_wday;
1907        stUTC.wMonth        = time_breakdown->tm_mon  + 1;
1908        stUTC.wYear         = time_breakdown->tm_year + 1900;
1909        stUTC.wMilliseconds = 0;
1910
1911        // Convert the last-write time to local time.
1912        if (!SystemTimeToFileTime(&stUTC, pTo))
1913        {
1914                syslog(LOG_ERR, "Failed to convert between time formats: %s",
1915                        GetErrorMessage(GetLastError()).c_str());
1916                return false;
1917        }
1918
1919        return true;
1920}
1921
1922#endif // WIN32
1923
Note: See TracBrowser for help on using the repository browser.