fix merge conflicts with master
[ardour.git] / libs / pbd / msvc / msvc_pbd.cc
1 /*
2     Copyright (C) 2009 John Emmas
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef COMPILER_MSVC
21
22 #include <WTypes.h>
23
24 extern "C" WINBASEAPI BOOL WINAPI
25 CreateHardLinkA( LPCSTR lpFileName,
26                                  LPCSTR lpExistingFileName,
27                                  LPSECURITY_ATTRIBUTES lpSecurityAttributes ); // Needs kernel32.lib on anything higher than Win2K
28
29 #include <algorithm>
30 #include <string>
31 #include <io.h>
32 #include <math.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <sys/stat.h>
37 #include <pbd/error.h>
38 #include <ardourext/misc.h>
39 #include <ardourext/pthread.h> // Should ensure that we include the right
40                                // version - but we'll check anyway, later
41
42 #include <glibmm.h>
43
44 #define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
45
46 struct timezone
47 {
48         int  tz_minuteswest; /* minutes W of Greenwich */
49         int  tz_dsttime;     /* type of dst correction */
50 };
51
52 PBD_API int PBD_APICALLTYPE
53 gettimeofday(struct timeval *__restrict tv, __timezone_ptr_t tz) // Does this need to be exported ?
54 {
55 FILETIME ft;
56 unsigned __int64 tmpres = 0;
57 static int tzflag = 0;
58
59         if (NULL != tv)
60         {
61                 GetSystemTimeAsFileTime(&ft);
62
63                 tmpres |= ft.dwHighDateTime;
64                 tmpres <<= 32;
65                 tmpres |= ft.dwLowDateTime;
66
67                 /*converting file time to unix epoch*/
68                 tmpres /= 10;  /*convert into microseconds*/
69                 tmpres -= DELTA_EPOCH_IN_MICROSECS;
70                 tv->tv_sec = (long)(tmpres / 1000000UL);
71                 tv->tv_usec = (long)(tmpres % 1000000UL);
72         }
73
74         if (NULL != tz)
75         {
76                 struct timezone *ptz = static_cast<struct timezone*> (tz);
77                 if (!tzflag)
78                 {
79                         _tzset();
80                         tzflag++;
81                 }
82                 if (ptz)
83                 {
84                         ptz->tz_minuteswest = _timezone / 60;
85                         ptz->tz_dsttime = _daylight;
86                 }
87         }
88
89         return 0;
90 }
91
92 // Define the default comparison operators for Windows (ptw32) 'pthread_t' (not used
93 // by Ardour AFAIK but would be needed if an array of 'pthread_t' had to be sorted).
94 #ifndef PTHREAD_H   // Defined by PTW32 (Linux and other versions define _PTHREAD_H)
95 #error "An incompatible version of 'pthread.h' is #included. Use only the Windows (ptw32) version!"
96 #else
97 bool operator>  (const pthread_t& lhs, const pthread_t& rhs)
98 {
99         return (std::greater<void*>()(lhs.p, rhs.p));
100 }
101
102 bool operator<  (const pthread_t& lhs, const pthread_t& rhs)
103 {
104         return (std::less<void*>()(lhs.p, rhs.p));
105 }
106
107 bool operator!= (const pthread_t& lhs, const pthread_t& rhs)
108 {
109         return (std::not_equal_to<void*>()(lhs.p, rhs.p));
110 }
111
112 bool operator== (const pthread_t& lhs, const pthread_t& rhs)
113 {
114         return (!(lhs != rhs));
115 }
116 #endif
117
118 // Functions supplied (later) to std::transform
119 //***************************************************************
120 //
121 //      invert_backslash()
122 //
123 // Examines a supplied ASCII character and (if the character is
124 // a backslash) converts it to a forward slash,
125 //
126 //      Returns:
127 //
128 //    The supplied character (converted, if it was a backslash)
129 //
130 char invert_backslash(char character)
131 {
132         if ('\\' == character)
133                 character = '/';
134
135         return (character);
136 }
137
138 //***************************************************************
139 //
140 //      invert_forwardslash()
141 //
142 // Examines a supplied ASCII character and (if the character is
143 // a forward slash) converts it to a backslash,
144 //
145 //      Returns:
146 //
147 //    The supplied character (converted, if it was a fwd slash)
148 //
149 char invert_forwardslash(char character)
150 {
151         if ('/' == character)
152                 character = '\\';
153
154         return (character);
155 }
156
157
158 //***************************************************************
159 //
160 //      pread()
161 //
162 // Emulates pread() using _lseek()/_read()/_lseek().
163 //
164 //      Returns:
165 //
166 //    On Success: The number of bytes read from the file
167 //    On Failure: -1
168 //
169 PBD_API ssize_t PBD_APICALLTYPE
170 pread(int handle, void *buf, size_t nbytes, off_t offset)
171 {
172 int old_errno;
173 ssize_t ret;
174
175         off_t old_offset = _tell(handle);
176
177         if (0 > old_offset)
178                 ret = (-1);
179         else
180         {
181                 _lseek(handle, offset, SEEK_SET);
182                 ret = _read(handle, buf, nbytes);
183
184                 old_errno = errno;
185                 _lseek(handle, old_offset, SEEK_SET);
186                 errno = old_errno;
187         }
188
189         return (ret);
190 }
191
192
193 //***************************************************************
194 //
195 //      pwrite()
196 //
197 // Emulates pwrite() using _lseek()/_write()/_lseek().
198 //
199 //      Returns:
200 //
201 //    On Success: The number of bytes written to the file
202 //    On Failure: -1
203 //
204 PBD_API ssize_t PBD_APICALLTYPE
205 pwrite(int handle, const void *buf, size_t nbytes, off_t offset)
206 {
207 int old_errno;
208 ssize_t ret;
209
210         off_t old_offset = _lseek(handle, offset, SEEK_SET);
211
212         if (0 > old_offset)
213                 ret = (-1);
214         else
215         {
216                 ret = _write(handle, buf, nbytes);
217
218                 old_errno = errno;
219                 _lseek(handle, old_offset, SEEK_SET);
220                 errno = old_errno;
221         }
222
223         return (ret);
224 }
225
226 //***************************************************************
227 //
228 //      round()
229 //
230 // Emulates round() using floor().
231 //
232 //      Returns:
233 //
234 //    On Success: The largest integer that is less than or
235 //                equal to 'x'.
236 //    On Failure: None
237 //
238 PBD_API double PBD_APICALLTYPE
239 round(double x)
240 {
241         return (floor(x));
242 }
243
244 namespace PBD {
245
246 //***************************************************************
247 //
248 //      TestForMinimumSpecOS()
249 //
250 // Tests the user's OS to see if it is Win2K or later (could be
251 // expanded quite easily to accommodate other OS's)
252 //
253 //      Returns:
254 //
255 //    On Success: TRUE (if the user's OS matches the minimum spec)
256 //    On Failure: FALSE otherwise
257 //
258 PBD_API bool PBD_APICALLTYPE
259 TestForMinimumSpecOS(char *revision /* currently ignored */)
260 {
261 bool bRet = true;
262 #ifdef PLATFORM_WINDOWS
263         bRet = false;
264         HINSTANCE hKernelDll = (HINSTANCE)dlopen("kernel32.dll", RTLD_NOW);
265
266         if (hKernelDll)
267         {
268                 // 'CreateHardLink()' is only available from Win2K onwards.
269                 if (NULL != dlsym(hKernelDll, "CreateHardLinkA"))
270                         bRet = true;
271
272                 dlclose(hKernelDll);
273         }
274 #endif
275         // Other OS's could be accommodated here
276
277         return (bRet);
278 }
279
280
281 //***************************************************************
282 //
283 //      realpath()
284 //
285 // Emulates POSIX realpath() using Win32 _fullpath().
286 //
287 //      Returns:
288 //
289 //    On Success: A pointer to the resolved (absolute) path
290 //    On Failure: NULL
291 //
292 PBD_API char* PBD_APICALLTYPE
293 realpath (const char *original_path, char resolved_path[_MAX_PATH+1])
294 {
295 char *pRet = NULL;
296 bool bIsSymLink = 0; // We'll probably need to test the incoming path
297                      // to find out if it points to a Windows shortcut
298                      // (or a hard link) and set this appropriately.
299         if (bIsSymLink)
300         {
301                 // At the moment I'm not sure if Windows '_fullpath()' is directly
302                 // equivalent to POSIX 'realpath()' - in as much as the latter will
303                 // resolve the supplied path if it happens to point to a symbolic
304                 // link ('_fullpath()' probably DOESN'T do this but I'm not really
305                 // sure if Ardour needs such functionality anyway). Therefore we'll
306                 // possibly need to add that functionality here at a later date.
307         }
308         else
309         {
310                 char temp[(MAX_PATH+1)*6]; // Allow for maximum length of a path in UTF8 characters
311
312                 // POSIX 'realpath()' requires that the buffer size is at
313                 // least PATH_MAX+1, so assume that the user knew this !!
314                 pRet = _fullpath(temp, Glib::locale_from_utf8(original_path).c_str(), _MAX_PATH);
315                 if (NULL != pRet)
316                         strcpy(resolved_path, Glib::locale_to_utf8(temp).c_str());
317         }
318
319         return (pRet);
320 }
321
322
323 //***************************************************************
324 //
325 //      opendir()
326 //
327 // Creates a pointer to a DIR structure, appropriately filled in
328 // and ready to begin a directory search iteration.
329 //
330 //      Returns:
331 //
332 //    On Success: Pointer to a (heap based) DIR structure
333 //    On Failure: NULL
334 //
335 PBD_API DIR* PBD_APICALLTYPE
336 opendir (const char *szPath)
337 {
338 wchar_t wpath[PATH_MAX+1];
339 unsigned int rc;
340 DIR *pDir = 0;
341
342         errno = 0;
343
344         if (!szPath)
345                 errno = EFAULT;
346
347         if ((!errno) && ('\0' == szPath[0]))
348                 errno = ENOTDIR;
349
350         // Determine if the given path really is a directory
351
352         if (!errno)
353                 if (0 == MultiByteToWideChar (CP_UTF8, 0, (LPCSTR)szPath, -1, (LPWSTR)wpath, sizeof(wpath)))
354                         errno = EFAULT;
355
356         if ((!errno) && ((rc = GetFileAttributesW(wpath)) == -1))
357                 errno = ENOENT;
358
359         if ((!errno) && (!(rc & FILE_ATTRIBUTE_DIRECTORY)))
360                 // Error. Entry exists but not a directory. */
361                 errno = ENOTDIR;
362
363         if (!errno)
364         {
365                 // Allocate enough memory to store DIR structure, plus
366                 // the complete directory path originally supplied.
367                 pDir = (DIR *)malloc(sizeof(DIR) + strlen(szPath) + strlen("\\") + strlen ("*"));
368
369                 if (!pDir)
370                 {
371                         // Error - out of memory
372                         errno = ENOMEM;
373                 }
374         }
375
376         if (!errno)
377         {
378                 // Create the search expression
379                 strcpy(pDir->dd_name, szPath);
380
381                 // Add a backslash if the path doesn't already end with one
382                 if (pDir->dd_name[0] != '\0' &&
383                         pDir->dd_name[strlen(pDir->dd_name) - 1] != '/' &&
384                         pDir->dd_name[strlen(pDir->dd_name) - 1] != '\\')
385                 {
386                         strcat (pDir->dd_name, "\\");
387                 }
388
389                 // Add the search pattern
390                 strcat(pDir->dd_name, "*");
391
392                 // Initialize handle to -1 so that a premature closedir()
393                 // doesn't try to call _findclose() on it.
394                 pDir->dd_handle = (-1);
395
396                 // Initialize the status
397                 pDir->dd_stat = 0;
398
399                 // Initialize the dirent structure. 'ino' and 'reclen' are invalid under Win32
400                 // and 'name' simply points at the appropriate part of the findfirst_t struct.
401                 pDir->dd_dir.d_ino = 0;
402                 pDir->dd_dir.d_reclen = 0;
403                 pDir->dd_dir.d_namlen = 0;
404                 strcpy(pDir->dd_dir.d_name, pDir->dd_dta.name);
405
406                 return (pDir);  // Succeeded
407         }
408
409         if (pDir)
410                 free (pDir);
411         return (DIR *) 0; // Failed
412 }
413
414
415 //***************************************************************
416 //
417 //      readdir()
418 //
419 // Return a pointer to a dirent struct, filled with information
420 // about the next entry in the directory.
421 //
422 //      Returns:
423 //
424 //    On Success: A pointer to the supplied DIR's 'dirent' struct
425 //    On Failure: NULL
426 //
427 PBD_API struct dirent* PBD_APICALLTYPE
428 readdir (DIR* pDir)
429 {
430 int old_errno = 0;
431 errno = 0;
432
433         // Check for valid DIR struct
434         if (!pDir)
435                 errno = EFAULT;
436
437         if ((strcmp(pDir->dd_dir.d_name, pDir->dd_dta.name)) && (!errno))
438                 // The structure does not seem to be set up correctly
439                 errno = EINVAL;
440         else
441         {
442                 if (pDir->dd_stat < 0)
443                 {
444                         // We have already returned all files in this directory
445                         // (or the structure has an invalid dd_stat).
446                         return (struct dirent *)0;
447                 }
448                 else if (pDir->dd_stat == 0)
449                 {
450                         // We haven't started the search yet.
451                         // Start the search
452                         pDir->dd_handle = _findfirst (Glib::locale_from_utf8(pDir->dd_name).c_str(), &(pDir->dd_dta));
453
454                         if (pDir->dd_handle == -1)
455                                 // The directory is empty
456                                 pDir->dd_stat = -1;
457                         else
458                                 pDir->dd_stat = 1;
459                 }
460                 else
461                 {
462                         // Do not return ENOENT on last file in directory
463                         old_errno = errno;
464
465                         // Get the next search entry
466                         if (_findnext (pDir->dd_handle, &(pDir->dd_dta)))
467                         {
468                                 // We are off the end or otherwise error
469                                 errno = old_errno;
470                                 _findclose (pDir->dd_handle);
471                                 pDir->dd_handle = -1;
472                                 pDir->dd_stat = -1;
473                         }
474                         else
475                                 // Update to indicate the correct status number
476                                 pDir->dd_stat++;
477                 }
478
479                 if (pDir->dd_stat > 0)
480                 {
481                         // We successfully got an entry. Details about the file are
482                         // already appropriately filled in except for the length of
483                         // file name.
484                         strcpy(pDir->dd_dir.d_name, pDir->dd_dta.name);
485                         pDir->dd_dir.d_namlen = strlen (pDir->dd_dir.d_name);
486                         return (&pDir->dd_dir); // Succeeded
487                 }
488         }
489
490         return (struct dirent *) 0; // Failed
491 }
492
493
494 //***************************************************************
495 //
496 //      closedir()
497 //
498 // Frees the resources allocated by opendir().
499 //
500 //      Returns:
501 //
502 //    On Success: 0
503 //    On Failure: -1
504 //
505 PBD_API int PBD_APICALLTYPE
506 closedir (DIR *pDir)
507 {
508 int rc = 0;
509
510         errno = 0;
511
512         if (!pDir)
513                 errno = EFAULT;
514         else
515         {
516                 if ((-1) != pDir->dd_handle)
517                         rc = _findclose (pDir->dd_handle);
518
519                 // Free the DIR structure
520                 free (pDir);
521
522                 return rc; // Succeeded
523         }
524
525         return (-1); // Failed
526 }
527
528 //***************************************************************
529 //
530 //      mkstemp()
531 //
532 // Emulates Linux mkstemp() using Win32 _mktemp() and _open() etc.
533 //
534 //      Returns:
535 //
536 //    On Success: A file descriptor for the opened file.
537 //    On Failure: (-1)
538 //
539 PBD_API int PBD_APICALLTYPE
540 mkstemp (char *template_name)
541 {
542 int ret = (-1);
543 char *szFileName;
544 char szTempPath[PATH_MAX+100]; // Just ensure we have plenty of buffer space
545
546         if (NULL != (szFileName = _mktemp(template_name)))
547         {
548                 if (0 != ::GetTempPathA(sizeof(szTempPath), szTempPath))
549                 {
550                         strcat(szTempPath, szFileName);
551                         ret = _open(szTempPath, (_O_CREAT|_O_BINARY|_O_TEMPORARY|_O_RDWR|_O_TRUNC), _S_IWRITE);
552                 }
553         }
554
555         return (ret);
556 }
557
558
559 //***************************************************************
560 //
561 //      ntfs_link()
562 //
563 // Emulates Linux link() using Win32 CreateHardLink()(NTFS only).
564 //
565 //      Returns:
566 //
567 //    On Success: Non-zero.
568 //    On Failure: Zero (call 'GetLastError()' to retrieve info)
569 //
570 PBD_API int PBD_APICALLTYPE
571 ntfs_link (const char *existing_filepath, const char *link_filepath)
572 {
573 int ret = 1; // 'ERROR_INVALID_FUNCTION'
574 bool bValidPath = false;
575
576         // Make sure we've been sent a valid input string
577         if (existing_filepath && link_filepath)
578         {
579                 std::string strRoot = existing_filepath;
580
581                 if ((1 < strRoot.length()) && ('\\' == existing_filepath[0]) && ('\\' == existing_filepath[1]))
582                 {
583                         int slashcnt = 0;
584
585                         // We've been sent a network path. Convert backslashes to forward slashes temporarily.
586                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
587
588                         // Now, if there are less than four slashes, add a fourth one or abort
589                         std::string::iterator iter = strRoot.begin();
590                         while ((slashcnt < 4) && (iter != strRoot.end()))
591                         {
592                                 if ('/' == (*iter))
593                                         slashcnt++;
594
595                                 ++iter;
596                         }
597
598                         if (slashcnt > 2)
599                         {
600                                 // If only 3 slashes were counted, add a trailing slash
601                                 if (slashcnt == 3)
602                                         strRoot += '/';
603
604                                 // Now find the position of the fourth slash
605                                 iter = strRoot.begin();
606                                 int charcnt = 0;
607                                 for (slashcnt=0; slashcnt<4;)
608                                 {
609                                         charcnt++;
610
611                                         if ('/' == (*iter))
612                                                 slashcnt++;
613
614                                         if (++iter == strRoot.end())
615                                                 break;
616                                 }
617
618                                 strRoot.resize(charcnt);
619                                 bValidPath = true;
620                         }
621                 }
622                 else
623                 {
624                         // Assume a standard Windows style path
625                         if (1 < strRoot.length() && (':' == existing_filepath[1]))
626                         {
627                                 // Convert backslashes to forward slashes temporarily.
628                                 std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
629
630                                 if (2 == strRoot.length())
631                                         strRoot += '/';
632
633                                 if ('/' == strRoot[2])
634                                 {
635                                         strRoot.resize(3);
636                                         bValidPath = true;
637                                 }
638                         }
639                 }
640
641                 if (bValidPath)
642                 {
643                         char szFileSystemType[_MAX_PATH+1];
644
645                         // Restore the original backslashes
646                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_forwardslash);
647
648                         // Windows only supports hard links for the NTFS filing
649                         // system, so let's make sure that's what we're using!!
650                         if (::GetVolumeInformationA(strRoot.c_str(), NULL, 0, NULL, NULL, NULL, szFileSystemType, _MAX_PATH+1))
651                         {
652                                 std::string strRootFileSystemType = szFileSystemType;
653                                 std::transform(strRootFileSystemType.begin(), strRootFileSystemType.end(), strRootFileSystemType.begin(), ::toupper);
654 #if (_WIN32_WINNT >= 0x0500)
655                                 if (0 == strRootFileSystemType.compare("NTFS"))
656                                 {
657                                         if (TestForMinimumSpecOS()) // Hard links were only available from Win2K onwards
658                                                 if (0 == CreateHardLinkA(link_filepath, existing_filepath, NULL))
659                                                 {       // Note that the above API call cannot create a link to a directory, so
660                                                         // should we also be checking that the supplied path was actually a file?
661                                                         ret = GetLastError();
662                                                 }
663                                                 else
664                                                         SetLastError(ret = 0); // 'NO_ERROR'
665                                 }
666                                 else
667                                 {
668                                         ret = 4300; // 'ERROR_INVALID_MEDIA'
669                                 }
670 #endif
671                         }
672                 }
673                 else
674                         ret = 123; // 'ERROR_INVALID_NAME'
675         }
676         else
677                 ret = 161; // 'ERROR_BAD_PATHNAME'
678
679         if (ret)
680         {
681                 SetLastError(ret);
682                 return (-1);
683         }
684         else
685                 return (0);
686 }
687
688
689 //***************************************************************
690 //
691 //      ntfs_unlink()
692 //
693 // Emulates Linux unlink() using Win32 DeleteFile()(NTFS only).
694 //
695 //      Returns:
696 //
697 //    On Success: Non-zero.
698 //    On Failure: Zero (call 'GetLastError()' to retrieve info)
699 //
700 PBD_API int PBD_APICALLTYPE
701 ntfs_unlink (const char *link_filepath)
702 {
703 int ret = 1; // 'ERROR_INVALID_FUNCTION'
704 bool bValidPath = false;
705
706         // Make sure we've been sent a valid input string
707         if (link_filepath)
708         {
709                 std::string strRoot = link_filepath;
710
711                 if ((1 < strRoot.length()) && ('\\' == link_filepath[0]) && ('\\' == link_filepath[1]))
712                 {
713                         int slashcnt = 0;
714
715                         // We've been sent a network path. Convert backslashes to forward slashes temporarily.
716                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
717
718                         // Now, if there are less than four slashes, add a fourth one or abort
719                         std::string::iterator iter = strRoot.begin();
720                         while ((slashcnt < 4) && (iter != strRoot.end()))
721                         {
722                                 if ('/' == (*iter))
723                                         slashcnt++;
724
725                                 ++iter;
726                         }
727
728                         if (slashcnt > 2)
729                         {
730                                 // If only 3 slashes were counted, add a trailing slash
731                                 if (slashcnt == 3)
732                                         strRoot += '/';
733
734                                 // Now find the position of the fourth slash
735                                 iter = strRoot.begin();
736                                 int charcnt = 0;
737                                 for (slashcnt=0; slashcnt<4;)
738                                 {
739                                         charcnt++;
740
741                                         if ('/' == (*iter))
742                                                 slashcnt++;
743
744                                         if (++iter == strRoot.end())
745                                                 break;
746                                 }
747
748                                 strRoot.resize(charcnt);
749                                 bValidPath = true;
750                         }
751                 }
752                 else
753                 {
754                         // Assume a standard Windows style path
755                         if (1 < strRoot.length() && (':' == link_filepath[1]))
756                         {
757                                 // Convert backslashes to forward slashes temporarily.
758                                 std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
759
760                                 if (2 == strRoot.length())
761                                         strRoot += '/';
762
763                                 if ('/' == strRoot[2])
764                                 {
765                                         strRoot.resize(3);
766                                         bValidPath = true;
767                                 }
768                         }
769                 }
770
771                 if (bValidPath)
772                 {
773                         char szFileSystemType[_MAX_PATH+1];
774
775                         // Restore the original backslashes
776                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_forwardslash);
777
778                         // Windows only supports hard links for the NTFS filing
779                         // system, so let's make sure that's what we're using!!
780                         if (::GetVolumeInformationA(strRoot.c_str(), NULL, 0, NULL, NULL, NULL, szFileSystemType, _MAX_PATH+1))
781                         {
782                                 std::string strRootFileSystemType = szFileSystemType;
783                                 std::transform(strRootFileSystemType.begin(), strRootFileSystemType.end(), strRootFileSystemType.begin(), ::toupper);
784 #if (_WIN32_WINNT >= 0x0500)
785                                 if (0 == strRootFileSystemType.compare("NTFS"))
786                                         if (TestForMinimumSpecOS()) // Hard links were only available from Win2K onwards
787                                                 if (0 == DeleteFileA(link_filepath))
788                                                         ret = GetLastError();
789                                                 else
790                                                         ret = 0; // 'NO_ERROR'
791 #endif
792                         }
793                 }
794                 else
795                         ret = 123; // 'ERROR_INVALID_NAME'
796         }
797         else
798                 ret = 161; // 'ERROR_BAD_PATHNAME'
799
800         if (ret)
801         {
802                 SetLastError(ret);
803                 return (-1);
804         }
805         else
806                 return (0);
807 }
808
809 }  // namespace PBD
810
811
812 //***************************************************************
813 //
814 //      dlopen()
815 //
816 // Emulates POSIX dlopen() using Win32 LoadLibrary().
817 //
818 //      Returns:
819 //
820 //    On Success: A handle to the opened DLL
821 //    On Failure: NULL
822 //
823 PBD_API void* PBD_APICALLTYPE
824 dlopen (const char *file_name, int mode)
825 {
826         // Note that 'mode' is ignored in Win32
827         return(::LoadLibraryA(Glib::locale_from_utf8(file_name).c_str()));
828 }
829
830
831 //***************************************************************
832 //
833 //      dlclose()
834 //
835 // Emulates POSIX dlclose() using Win32 FreeLibrary().
836 //
837 //      Returns:
838 //
839 //    On Success: A non-zero number
840 //    On Failure: 0
841 //
842 PBD_API int PBD_APICALLTYPE
843 dlclose (void *handle)
844 {
845         return (::FreeLibrary((HMODULE)handle));
846 }
847
848
849 //***************************************************************
850 //
851 //      dlsym()
852 //
853 // Emulates POSIX dlsym() using Win32 GetProcAddress().
854 //
855 //      Returns:
856 //
857 //    On Success: A pointer to the found function or symbol
858 //    On Failure: NULL
859 //
860 PBD_API void* PBD_APICALLTYPE
861 dlsym (void *handle, const char *symbol_name)
862 {
863         // First test for RTLD_DEFAULT and RTLD_NEXT
864         if ((handle == 0/*RTLD_DEFAULT*/) || (handle == ((void *) -1L)/*RTLD_NEXT*/))
865         {
866                 return 0; // Not yet supported for Win32
867         }
868         else
869                 return (::GetProcAddress((HMODULE)handle, symbol_name));
870 }
871
872 #define LOCAL_ERROR_BUF_SIZE 1024
873 static char szLastWinError[LOCAL_ERROR_BUF_SIZE];
874 //***************************************************************
875 //
876 //      dlerror()
877 //
878 // Emulates POSIX dlerror() using Win32 GetLastError().
879 //
880 //      Returns:
881 //
882 //    On Success: The translated message corresponding to the
883 //                last error
884 //    On Failure: NULL (if the last error was ERROR_SUCCESS)
885 //
886 PBD_API char* PBD_APICALLTYPE
887 dlerror ()
888 {
889         DWORD dwLastErrorId = GetLastError();
890         if (ERROR_SUCCESS == dwLastErrorId)
891                 return 0;
892         else
893         {
894                 if (0 == FormatMessage(
895                                         FORMAT_MESSAGE_FROM_SYSTEM,
896                                         NULL,
897                                         dwLastErrorId,
898                                         0,
899                                         szLastWinError,
900                                         LOCAL_ERROR_BUF_SIZE,
901                                         0))
902                 {
903                         sprintf(szLastWinError, "Could not decipher the previous error message");
904                 }
905
906                 // POSIX dlerror() seems to reset the
907                 // error system, so emulate that here
908                 SetLastError(ERROR_SUCCESS);
909         }
910
911         return(szLastWinError);
912 }
913
914 #endif  // COMPILER_MSVC