Added initial unfs3 sources for version 0.9.22+dfsg-1maemo2
[unfs3] / unfs3 / winsupport.c
1
2 /*
3  * unfs3 Windows compatibility layer
4  * Copyright 2006 Peter Åstrand <astrand@cendio.se> for Cendio AB
5  * see file LICENSE for license details
6  */
7
8 #ifdef WIN32
9 #define _WIN32_WINDOWS 0x0410          /* We require Windows 98 or later For
10                                           GetLongPathName */
11 #include <errno.h>
12 #include <stdio.h>
13 #include "winsupport.h"
14 #include "Config/exports.h"
15 #include "daemon.h"
16 #include <assert.h>
17 #include <windows.h>
18 #include <wincrypt.h>
19 #include <ctype.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <direct.h>
23 #include <dirent.h>
24 #include <locale.h>
25
26 #define MAX_NUM_DRIVES 26
27 #define FT70SEC 11644473600LL          /* seconds between 1601-01-01 and
28                                           1970-01-01 */
29 #define FT80SEC 315529200              /* seconds between 1970-01-01 and
30                                           1980-01-01 */
31
32 #define wsizeof(x) (sizeof(x)/sizeof(wchar_t))
33
34 typedef struct _fdname {
35     int fd;
36     char *name;
37     struct _fdname *next;
38 } fdname;
39
40 static fdname *fdnames = NULL;
41
42 static char *get_fdname(int fd)
43 {
44     fdname *fn;
45
46     for (fn = fdnames; fn; fn = fn->next) {
47         if (fn->fd == fd) {
48             return fn->name;
49             break;
50         }
51     }
52
53     assert(0);
54     return NULL;
55 }
56
57 static int add_fdname(int fd, const char *name)
58 {
59     fdname *fn;
60
61     fn = malloc(sizeof(fdname));
62     if (!fn) {
63         logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
64         return -1;
65     }
66
67     fn->fd = fd;
68     fn->name = strdup(name);
69     fn->next = fdnames;
70     fdnames = fn;
71
72     return fd;
73 }
74
75 static void remove_fdname(int fd)
76 {
77     fdname *fn, **prevnext = &fdnames;
78
79     for (fn = fdnames; fn; fn = fn->next) {
80         if (fn->fd == fd) {
81             *prevnext = fn->next;
82             free(fn->name);
83             free(fn);
84             break;
85         }
86         prevnext = &fn->next;
87     }
88 }
89
90 /* 
91  * The following UTF-8 validation is borrowed from
92  * ftp://ftp.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c.
93  */
94
95 /*
96  * Copyright 2001-2004 Unicode, Inc.
97  * 
98  * Disclaimer
99  * 
100  * This source code is provided as is by Unicode, Inc. No claims are
101  * made as to fitness for any particular purpose. No warranties of any
102  * kind are expressed or implied. The recipient agrees to determine
103  * applicability of information provided. If this file has been
104  * purchased on magnetic or optical media from Unicode, Inc., the
105  * sole remedy for any claim will be exchange of defective media
106  * within 90 days of receipt.
107  * 
108  * Limitations on Rights to Redistribute This Code
109  * 
110  * Unicode, Inc. hereby grants the right to freely use the information
111  * supplied in this file in the creation of products supporting the
112  * Unicode Standard, and to make copies of this file in any form
113  * for internal or external distribution as long as this notice
114  * remains attached.
115  */
116
117 /*
118  * Index into the table below with the first byte of a UTF-8 sequence to
119  * get the number of trailing bytes that are supposed to follow it.
120  * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
121  * left as-is for anyone who may want to do such conversion, which was
122  * allowed in earlier algorithms.
123  */
124 static const char trailingBytesForUTF8[256] = {
125     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
135     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
136     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
137     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
138     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
139     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
140     3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
141 };
142
143 /*
144  * Utility routine to tell whether a sequence of bytes is legal UTF-8.
145  * This must be called with the length pre-determined by the first byte.
146  * If not calling this from ConvertUTF8to*, then the length can be set by:
147  *  length = trailingBytesForUTF8[*source]+1;
148  * and the sequence is illegal right away if there aren't that many bytes
149  * available.
150  * If presented with a length > 4, this returns 0.  The Unicode
151  * definition of UTF-8 goes up to 4-byte sequences.
152  */
153
154 static int isLegalUTF8(const unsigned char *source, int length)
155 {
156     unsigned char a;
157     const unsigned char *srcptr = source + length;
158
159     switch (length) {
160         default:
161             return 0;
162             /* Everything else falls through when "1"... */
163         case 4:
164             if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
165                 return 0;
166         case 3:
167             if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
168                 return 0;
169         case 2:
170             if ((a = (*--srcptr)) > 0xBF)
171                 return 0;
172
173             switch (*source) {
174                     /* no fall-through in this inner switch */
175                 case 0xE0:
176                     if (a < 0xA0)
177                         return 0;
178                     break;
179                 case 0xED:
180                     if (a > 0x9F)
181                         return 0;
182                     break;
183                 case 0xF0:
184                     if (a < 0x90)
185                         return 0;
186                     break;
187                 case 0xF4:
188                     if (a > 0x8F)
189                         return 0;
190                     break;
191                 default:
192                     if (a < 0x80)
193                         return 0;
194             }
195
196         case 1:
197             if (*source >= 0x80 && *source < 0xC2)
198                 return 0;
199     }
200     if (*source > 0xF4)
201         return 0;
202     return 1;
203 }
204
205 /* End of code borrowed from ConvertUTF.c */
206
207 int isLegalUTF8String(const unsigned char *source)
208 {
209     const unsigned char *seq, *sourceend;
210     int seqlen;
211
212     sourceend = source + strlen(source);
213     seq = source;
214
215     while (seq < sourceend) {
216         seqlen = trailingBytesForUTF8[*seq] + 1;
217         if (!isLegalUTF8(seq, seqlen))
218             return 0;
219         seq += seqlen;
220     }
221
222     return 1;
223 }
224
225 /* Translate an internal representation of a path (like /c/home) to
226    a Windows path (like c:\home) */
227 static wchar_t *intpath2winpath(const char *intpath)
228 {
229     wchar_t *winpath;
230     int winpath_len;
231     wchar_t *slash;
232     const char *lastrootslash;
233     wchar_t *lastslash;
234     size_t intlen;
235
236     /* Verify that input is valid UTF-8. We cannot use MB_ERR_INVALID_CHARS
237        to MultiByteToWideChar, since it's only available in late versions of
238        Windows. */
239     if (!isLegalUTF8String(intpath)) {
240         logmsg(LOG_CRIT, "intpath2winpath: Illegal UTF-8 string:%s", intpath);
241         return NULL;
242     }
243
244     /* Skip over multiple root slashes for paths like ///home/john */
245     lastrootslash = intpath;
246     while (*lastrootslash == '/')
247         lastrootslash++;
248     if (lastrootslash != intpath)
249         lastrootslash--;
250
251     intlen = strlen(lastrootslash);
252     /* One extra for /c -> c:\ */
253     winpath_len = sizeof(wchar_t) * (intlen + 2);
254     winpath = malloc(winpath_len);
255     if (!winpath) {
256         logmsg(LOG_CRIT, "intpath2winpath: Unable to allocate memory");
257         return NULL;
258     }
259
260     if (!MultiByteToWideChar
261         (CP_UTF8, 0, lastrootslash, -1, winpath, winpath_len)) {
262         logmsg(LOG_CRIT, "intpath2winpath: MultiByteToWideChar failed");
263         return NULL;
264     }
265
266     /* If path ends with /.., chop of the last component. Eventually, we
267        might want to eliminate all occurances of .. */
268     lastslash = wcsrchr(winpath, '/');
269     if (!wcscmp(lastslash, L"/..")) {
270         *lastslash = '\0';
271         lastslash = wcsrchr(winpath, '/');
272         *lastslash = '\0';
273     }
274
275     /* Translate /x -> x:/ and /x/something -> x:/something */
276     if ((winpath[0] == '/') && winpath[1]) {
277         switch (winpath[2]) {
278             case '\0':
279                 winpath[2] = '/';
280                 winpath[3] = '\0';
281                 /* fall through */
282
283             case '/':
284                 winpath[0] = winpath[1];
285                 winpath[1] = ':';
286                 break;
287
288             default:
289                 break;
290         }
291     }
292
293     while ((slash = wcschr(winpath, '/')) != NULL) {
294         *slash = '\\';
295     }
296
297     return winpath;
298 }
299
300 int win_seteuid(U(uid_t euid))
301 {
302     return 0;
303 }
304
305 int win_setegid(U(gid_t egid))
306 {
307     return 0;
308 }
309
310 int win_truncate(const char *path, off_t length)
311 {
312     int fd, ret, saved_errno;
313
314     fd = win_open(path, O_WRONLY);
315     if (fd < 0)
316         return -1;
317     ret = chsize(fd, length);
318     saved_errno = errno;
319     win_close(fd);
320     errno = saved_errno;
321
322     return ret;
323 }
324
325 int win_chown(U(const char *path), U(uid_t owner), U(gid_t group))
326 {
327     errno = EINVAL;
328     return -1;
329 }
330
331 int win_fchown(U(int fd), U(uid_t owner), U(gid_t group))
332 {
333     errno = EINVAL;
334     return -1;
335 }
336
337 int win_fchmod(int fildes, mode_t mode)
338 {
339     wchar_t *winpath;
340     int ret;
341
342     winpath = intpath2winpath(get_fdname(fildes));
343     if (!winpath) {
344         errno = EINVAL;
345         return -1;
346     }
347
348     ret = _wchmod(winpath, mode);
349     free(winpath);
350     return ret;
351 }
352
353 int inet_aton(const char *cp, struct in_addr *addr)
354 {
355     addr->s_addr = inet_addr(cp);
356     return (addr->s_addr == INADDR_NONE) ? 0 : 1;
357 }
358
359 /* 
360    If you need a good laugh, take a look at the "Suggested Interix
361    replacement" at:
362    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/UCMGch10.asp
363 */
364 ssize_t pread(int fd, void *buf, size_t count, off_t offset)
365 {
366     ssize_t size;
367     off_t ret;
368
369     if ((ret = lseek(fd, offset, SEEK_SET)) < 0)
370         return -1;
371     size = read(fd, buf, count);
372     return size;
373 }
374
375 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
376 {
377     ssize_t size;
378     off_t ret;
379     HANDLE h;
380     FILETIME ft;
381     SYSTEMTIME st;
382     ULARGE_INTEGER fti;
383
384     if ((ret = lseek(fd, offset, SEEK_SET)) < 0)
385         return -1;
386     size = write(fd, buf, count);
387
388     /* Since we are using the CreationTime attribute as "ctime", we need to
389        update it. From RFC1813: "Writing to the file changes the ctime in
390        addition to the mtime." */
391     h = (HANDLE) _get_osfhandle(fd);
392     GetSystemTime(&st);
393     SystemTimeToFileTime(&st, &ft);
394     /* Ceil up to nearest even second */
395     fti.LowPart = ft.dwLowDateTime;
396     fti.HighPart = ft.dwHighDateTime;
397     fti.QuadPart = ((fti.QuadPart + 20000000 - 1) / 20000000) * 20000000;
398     ft.dwLowDateTime = fti.LowPart;
399     ft.dwHighDateTime = fti.HighPart;
400     if (!SetFileTime(h, &ft, NULL, NULL)) {
401         fprintf(stderr,
402                 "warning: pwrite: SetFileTime failed with error %ld\n",
403                 GetLastError());
404     }
405
406     return size;
407 }
408
409 void syslog(U(int priority), U(const char *format), ...)
410 {
411     assert(0);
412 }
413
414 int win_init()
415 {
416     WORD winsock_ver;
417     WSADATA wsadata;
418
419     /* Set up locale, so that string compares works correctly */
420     setlocale(LC_ALL, "");
421
422     /* Verify that -s is used */
423     if (!opt_singleuser) {
424         fprintf(stderr, "Single-user mode is required on this platform.\n");
425         exit(1);
426     }
427
428     /* Verify that -d is used */
429     if (opt_detach) {
430         fprintf(stderr,
431                 "Foreground (debug) mode is required on this platform.\n");
432         exit(1);
433     }
434
435     /* init winsock */
436     winsock_ver = MAKEWORD(1, 1);
437     if (WSAStartup(winsock_ver, &wsadata)) {
438         fprintf(stderr, "Unable to initialise WinSock\n");
439         exit(1);
440     }
441     if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) {
442         fprintf(stderr, "WinSock version is incompatible with 1.1\n");
443         WSACleanup();
444         exit(1);
445     }
446
447     /* disable error popups, for example from drives not ready */
448     SetErrorMode(SEM_FAILCRITICALERRORS);
449
450     return 0;
451 }
452
453 void win_shutdown()
454 {
455     WSACleanup();
456 }
457
458 /* Wrapper for Windows stat function, which provides
459    st_dev and st_ino. These are calculated as follows:
460
461    st_dev is set to the drive number (0=A 1=B ...). Our virtual root
462    "/" gets a st_dev of 0xff. 
463
464    st_ino is hashed from the full file path. Each half produces a 32
465    bit hash. These are concatenated to a 64 bit value. The risk that
466    st_ino is the same for two files on the system is, if I'm not
467    mistaken, b=pigeon(2**32, f)**2. For f=1000, b=1e-08. By using a 64
468    bit hash function this risk can be lowered. Possible future
469    enhancement.
470
471    pigeon() can be calculated in Python with:
472    
473    def pigeon(m, n):
474        res = 1.0
475        for i in range(m - n + 1, m):
476            res = res * i / m
477        return 1 - res
478 */
479 int win_stat(const char *file_name, backend_statstruct * buf)
480 {
481     wchar_t *winpath;
482     int ret;
483     wchar_t pathbuf[4096];
484     int retval;
485     size_t namelen;
486     wchar_t *splitpoint;
487     char savedchar;
488     struct _stat win_statbuf;
489
490     /* Special case: Our top-level virtual root, containing each drive
491        represented as a directory. Compare with "My Computer" etc. This
492        virtual root has a hardcoded hash value of 1, to simplify debugging
493        etc. */
494     if (!strcmp(file_name, "/")) {
495         buf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR;
496         buf->st_nlink = MAX_NUM_DRIVES + 3;     /* 3 extra for: . .. / */
497         buf->st_uid = 1;
498         buf->st_gid = 1;
499         buf->st_rdev = 0;
500         buf->st_size = 4096;
501         buf->st_atime = 0;
502         buf->st_mtime = 0;
503         buf->st_ctime = 0;
504         buf->st_dev = 0xff;
505         buf->st_ino = 1;
506         return 0;
507     }
508
509     winpath = intpath2winpath(file_name);
510     if (!winpath) {
511         errno = EINVAL;
512         return -1;
513     }
514
515     ret = _wstat(winpath, &win_statbuf);
516     if (ret < 0) {
517         free(winpath);
518         return ret;
519     }
520
521     /* Copy values to our struct */
522     buf->st_mode = win_statbuf.st_mode;
523     buf->st_nlink = win_statbuf.st_nlink;
524     buf->st_uid = win_statbuf.st_uid;
525     buf->st_gid = win_statbuf.st_gid;
526     buf->st_rdev = win_statbuf.st_rdev;
527     buf->st_size = win_statbuf.st_size;
528     buf->st_atime = win_statbuf.st_atime;
529     buf->st_mtime = win_statbuf.st_mtime;
530     buf->st_ctime = win_statbuf.st_ctime;
531     buf->st_blocks = win_statbuf.st_size / 512;
532
533     retval = GetFullPathNameW(winpath, wsizeof(pathbuf), pathbuf, NULL);
534     if (!retval) {
535         errno = ENOENT;
536         return -1;
537     }
538
539     /* Set st_dev to the drive number */
540     buf->st_dev = tolower(pathbuf[0]) - 'a';
541
542     /* GetLongPathName fails if called with only x:\, and drive x is not
543        ready. So, only call it for other paths. */
544     if (pathbuf[0] && wcscmp(pathbuf + 1, L":\\")) {
545         retval = GetLongPathNameW(pathbuf, pathbuf, wsizeof(pathbuf));
546         if (!retval || (unsigned) retval > wsizeof(pathbuf)) {
547             /* Strangely enough, GetLongPathName returns
548                ERROR_SHARING_VIOLATION for locked files, such as hiberfil.sys 
549              */
550             if (GetLastError() != ERROR_SHARING_VIOLATION) {
551                 errno = ENAMETOOLONG;
552                 return -1;
553             }
554         }
555     }
556
557     /* Hash st_ino, by splitting in two halves */
558     namelen = wcslen(pathbuf);
559     splitpoint = &pathbuf[namelen / 2];
560     savedchar = *splitpoint;
561     *splitpoint = '\0';
562     buf->st_ino = wfnv1a_32(pathbuf, 0);
563     assert(sizeof(buf->st_ino) == 8);
564     buf->st_ino = buf->st_ino << 32;
565     *splitpoint = savedchar;
566     buf->st_ino |= wfnv1a_32(splitpoint, 0);
567
568 #if 0
569     fprintf(stderr,
570             "win_stat: file=%s, ret=%d, st_dev=0x%x, st_ino=0x%I64x\n",
571             file_name, ret, buf->st_dev, buf->st_ino);
572 #endif
573     free(winpath);
574     return ret;
575 }
576
577 int win_open(const char *pathname, int flags, ...)
578 {
579     va_list args;
580     mode_t mode;
581     int fd;
582     wchar_t *winpath;
583
584     va_start(args, flags);
585     mode = va_arg(args, int);
586
587     va_end(args);
588
589     winpath = intpath2winpath(pathname);
590     if (!winpath) {
591         errno = EINVAL;
592         return -1;
593     }
594
595     fd = _wopen(winpath, flags | O_BINARY, mode);
596     free(winpath);
597     if (fd < 0) {
598         return fd;
599     }
600
601     return add_fdname(fd, pathname);
602
603 }
604
605 int win_close(int fd)
606 {
607     remove_fdname(fd);
608     return close(fd);
609 }
610
611 int win_fstat(int fd, backend_statstruct * buf)
612 {
613     return win_stat(get_fdname(fd), buf);
614 }
615
616 /*
617   opendir implementation which emulates a virtual root with the drive
618   letters presented as directories. 
619 */
620 UNFS3_WIN_DIR *win_opendir(const char *name)
621 {
622     wchar_t *winpath;
623     UNFS3_WIN_DIR *ret;
624
625     ret = malloc(sizeof(UNFS3_WIN_DIR));
626     if (!ret) {
627         logmsg(LOG_CRIT, "win_opendir: Unable to allocate memory");
628         return NULL;
629     }
630
631     if (!strcmp("/", name)) {
632         /* Emulate root */
633         ret->stream = NULL;
634         ret->currentdrive = 0;
635         ret->logdrives = GetLogicalDrives();
636     } else {
637         winpath = intpath2winpath(name);
638         if (!winpath) {
639             free(ret);
640             errno = EINVAL;
641             return NULL;
642         }
643
644         ret->stream = _wopendir(winpath);
645         free(winpath);
646         if (ret->stream == NULL) {
647             free(ret);
648             ret = NULL;
649         }
650     }
651
652     return ret;
653 }
654
655 struct dirent *win_readdir(UNFS3_WIN_DIR * dir)
656 {
657     if (dir->stream == NULL) {
658         /* Emulate root */
659         for (; dir->currentdrive < MAX_NUM_DRIVES; dir->currentdrive++) {
660             if (dir->logdrives & 1 << dir->currentdrive)
661                 break;
662         }
663
664         if (dir->currentdrive < MAX_NUM_DRIVES) {
665             dir->de.d_name[0] = 'a' + dir->currentdrive;
666             dir->de.d_name[1] = '\0';
667             dir->currentdrive++;
668             return &dir->de;
669         } else {
670             return NULL;
671         }
672     } else {
673         struct _wdirent *de;
674
675         de = _wreaddir(dir->stream);
676         if (!de) {
677             return NULL;
678         }
679
680         if (!WideCharToMultiByte
681             (CP_UTF8, 0, de->d_name, -1, dir->de.d_name,
682              sizeof(dir->de.d_name), NULL, NULL)) {
683             logmsg(LOG_CRIT, "win_readdir: WideCharToMultiByte failed");
684             return NULL;
685         }
686         return &dir->de;
687     }
688 }
689
690 int win_closedir(UNFS3_WIN_DIR * dir)
691 {
692     if (dir->stream == NULL) {
693         free(dir);
694         return 0;
695     } else {
696         return _wclosedir(dir->stream);
697     }
698 }
699
700 void openlog(U(const char *ident), U(int option), U(int facility))
701 {
702
703 }
704
705 char *win_realpath(const char *path, char *resolved_path)
706 {
707     return normpath(path, resolved_path);
708 }
709
710 int win_readlink(U(const char *path), U(char *buf), U(size_t bufsiz))
711 {
712     errno = ENOSYS;
713     return -1;
714 }
715
716 int win_mkdir(const char *pathname, U(mode_t mode))
717 {
718     wchar_t *winpath;
719     int ret;
720
721     if (!strcmp("/", pathname)) {
722         /* Emulate root */
723         errno = EROFS;
724         return -1;
725     }
726
727     winpath = intpath2winpath(pathname);
728     if (!winpath) {
729         errno = EINVAL;
730         return -1;
731     }
732
733     /* FIXME: Use mode */
734     ret = _wmkdir(winpath);
735     free(winpath);
736     return ret;
737 }
738
739 int win_symlink(U(const char *oldpath), U(const char *newpath))
740 {
741     errno = ENOSYS;
742     return -1;
743 }
744
745 int win_mknod(U(const char *pathname), U(mode_t mode), U(dev_t dev))
746 {
747     errno = ENOSYS;
748     return -1;
749 }
750
751 int win_mkfifo(U(const char *pathname), U(mode_t mode))
752 {
753     errno = ENOSYS;
754     return -1;
755 }
756
757 int win_link(U(const char *oldpath), U(const char *newpath))
758 {
759     errno = ENOSYS;
760     return -1;
761 }
762
763 int win_statvfs(const char *path, backend_statvfsstruct * buf)
764 {
765     wchar_t *winpath;
766     DWORD SectorsPerCluster;
767     DWORD BytesPerSector;
768     DWORD NumberOfFreeClusters;
769     DWORD TotalNumberOfClusters;
770     ULARGE_INTEGER FreeBytesAvailable;
771     ULARGE_INTEGER TotalNumberOfBytes;
772     ULARGE_INTEGER TotalNumberOfFreeBytes;
773
774     if (!strcmp("/", path)) {
775         /* Emulate root */
776         buf->f_bsize = 1024;
777         buf->f_blocks = 1024;
778         buf->f_bfree = 0;
779         buf->f_bavail = 0;
780         buf->f_files = 1024;
781         buf->f_ffree = 0;
782         return 0;
783     }
784
785     winpath = intpath2winpath(path);
786     if (!winpath) {
787         errno = EINVAL;
788         return -1;
789     }
790
791     winpath[3] = '\0';                 /* Cut off after x:\ */
792
793     if (!GetDiskFreeSpaceW
794         (winpath, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters,
795          &TotalNumberOfClusters)) {
796         errno = EIO;
797         return -1;
798     }
799
800     if (!GetDiskFreeSpaceExW
801         (winpath, &FreeBytesAvailable, &TotalNumberOfBytes,
802          &TotalNumberOfFreeBytes)) {
803         errno = EIO;
804         return -1;
805     }
806
807     buf->f_bsize = BytesPerSector;
808     buf->f_blocks = TotalNumberOfBytes.QuadPart / BytesPerSector;
809     buf->f_bfree = TotalNumberOfFreeBytes.QuadPart / BytesPerSector;
810     buf->f_bavail = FreeBytesAvailable.QuadPart / BytesPerSector;
811     buf->f_files = buf->f_blocks / SectorsPerCluster;
812     buf->f_ffree = buf->f_bfree / SectorsPerCluster;
813     free(winpath);
814     return 0;
815 }
816
817 int win_remove(const char *pathname)
818 {
819     wchar_t *winpath;
820     int ret;
821
822     if (!strcmp("/", pathname)) {
823         /* Emulate root */
824         errno = EROFS;
825         return -1;
826     }
827
828     winpath = intpath2winpath(pathname);
829     if (!winpath) {
830         errno = EINVAL;
831         return -1;
832     }
833
834     ret = _wremove(winpath);
835     free(winpath);
836     return ret;
837 }
838
839 int win_chmod(const char *path, mode_t mode)
840 {
841     wchar_t *winpath;
842     int ret;
843
844     if (!strcmp("/", path)) {
845         /* Emulate root */
846         errno = EROFS;
847         return -1;
848     }
849
850     winpath = intpath2winpath(path);
851     if (!winpath) {
852         errno = EINVAL;
853         return -1;
854     }
855
856     ret = _wchmod(winpath, mode);
857     free(winpath);
858     return ret;
859 }
860
861 /* 
862    If creation is false, the LastAccessTime will be set according to
863    times->actime. Otherwise, CreationTime will be set. LastWriteTime
864    is always set according to times->modtime.
865 */
866 static int win_utime_creation(const char *path, const struct utimbuf *times,
867                               int creation)
868 {
869     wchar_t *winpath;
870     int ret = 0;
871     HANDLE h;
872     ULARGE_INTEGER fti;
873     FILETIME xtime, mtime;
874
875     if (!strcmp("/", path)) {
876         /* Emulate root */
877         errno = EROFS;
878         return -1;
879     }
880
881     winpath = intpath2winpath(path);
882     if (!winpath) {
883         errno = EINVAL;
884         return -1;
885     }
886
887     /* Unfortunately, we cannot use utime(), since it doesn't support
888        directories. */
889     fti.QuadPart = UInt32x32To64(times->actime + FT70SEC, 10000000);
890     xtime.dwHighDateTime = fti.HighPart;
891     xtime.dwLowDateTime = fti.LowPart;
892     fti.QuadPart = UInt32x32To64(times->modtime + FT70SEC, 10000000);
893     mtime.dwHighDateTime = fti.HighPart;
894     mtime.dwLowDateTime = fti.LowPart;
895
896     h = CreateFileW(winpath, FILE_WRITE_ATTRIBUTES,
897                     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
898                     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
899
900     if (!SetFileTime
901         (h, creation ? &xtime : NULL, creation ? NULL : &xtime, &mtime)) {
902         errno = EACCES;
903         ret = -1;
904     }
905
906     CloseHandle(h);
907     free(winpath);
908     return ret;
909 }
910
911 int win_utime(const char *path, const struct utimbuf *times)
912 {
913     return win_utime_creation(path, times, FALSE);
914 }
915
916 int win_rmdir(const char *path)
917 {
918     wchar_t *winpath;
919     int ret;
920
921     if (!strcmp("/", path)) {
922         /* Emulate root */
923         errno = EROFS;
924         return -1;
925     }
926
927     winpath = intpath2winpath(path);
928     if (!winpath) {
929         errno = EINVAL;
930         return -1;
931     }
932
933     ret = _wrmdir(winpath);
934     free(winpath);
935     return ret;
936 }
937
938 int win_rename(const char *oldpath, const char *newpath)
939 {
940     wchar_t *oldwinpath, *newwinpath;
941     int ret;
942
943     if (!strcmp("/", oldpath) && !strcmp("/", newpath)) {
944         /* Emulate root */
945         errno = EROFS;
946         return -1;
947     }
948
949     oldwinpath = intpath2winpath(oldpath);
950     if (!oldwinpath) {
951         errno = EINVAL;
952         return -1;
953     }
954     newwinpath = intpath2winpath(newpath);
955     if (!newwinpath) {
956         free(oldwinpath);
957         errno = EINVAL;
958         return -1;
959     }
960
961     ret = _wrename(oldwinpath, newwinpath);
962     free(oldwinpath);
963     free(newwinpath);
964     return ret;
965 }
966
967 int win_gen_nonce(char *nonce)
968 {
969     HCRYPTPROV hCryptProv;
970
971     if (!CryptAcquireContext
972         (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
973         logmsg(LOG_ERR, "CryptAcquireContext failed with error 0x%lx",
974                GetLastError());
975         return -1;
976     }
977
978     if (!CryptGenRandom(hCryptProv, 32, nonce)) {
979         logmsg(LOG_ERR, "CryptGenRandom failed with error 0x%lx",
980                GetLastError());
981         return -1;
982     }
983
984     if (!CryptReleaseContext(hCryptProv, 0)) {
985         logmsg(LOG_ERR, "CryptReleaseContext failed with error 0x%lx",
986                GetLastError());
987         return -1;
988     }
989
990     return 0;
991 }
992
993 /* Just like strncasecmp, but compare two UTF8 strings. Limited to 4096 chars. */
994 int win_utf8ncasecmp(const char *s1, const char *s2, size_t n)
995 {
996     wchar_t ws1[4096], ws2[4096];
997     int converted;
998
999     /* Make sure input is valid UTF-8 */
1000     if (!isLegalUTF8String(s1)) {
1001         logmsg(LOG_CRIT, "win_utf8ncasecmp: Illegal UTF-8 string:%s", s1);
1002         return -1;
1003     }
1004     if (!isLegalUTF8String(s2)) {
1005         logmsg(LOG_CRIT, "win_utf8ncasecmp: Illegal UTF-8 string:%s", s2);
1006         return -1;
1007     }
1008
1009     /* Convert both strings to wide chars */
1010     converted = MultiByteToWideChar(CP_UTF8, 0, s1, n, ws1, wsizeof(ws1));
1011     if (!converted) {
1012         logmsg(LOG_CRIT, "win_utf8ncasecmp: MultiByteToWideChar failed");
1013         return -1;
1014     }
1015     ws1[converted] = '\0';
1016     converted = MultiByteToWideChar(CP_UTF8, 0, s2, n, ws2, wsizeof(ws2));
1017     if (!converted) {
1018         logmsg(LOG_CRIT, "win_utf8ncasecmp: MultiByteToWideChar failed");
1019         return 1;
1020     }
1021     ws2[converted] = '\0';
1022
1023     /* compare */
1024     return _wcsicmp(ws1, ws2);
1025 }
1026
1027 static void win_verf_to_ubuf(struct utimbuf *ubuf, createverf3 verf)
1028 {
1029     ubuf->actime = verf[0] | verf[1] << 8 | verf[2] << 16 | verf[3] << 24;
1030     ubuf->modtime = verf[4] | verf[5] << 8 | verf[6] << 16 | verf[7] << 24;
1031
1032     /* FAT can only store dates in the interval 1980-01-01 to 2107-12-31.
1033        However, since the utime interface uses Epoch time, we are further
1034        limited to 1980-01-01 to 2038-01-19, assuming 32 bit signed time_t.
1035        math.log(2**31-1 - FT80SEC, 2) = 30.7, which means that we can only
1036        use 30 bits. */
1037     ubuf->actime &= 0x3fffffff;
1038     ubuf->actime += FT80SEC;
1039     ubuf->modtime &= 0x3fffffff;
1040     ubuf->modtime += FT80SEC;
1041     /* While FAT CreationTime has a resolution of 10 ms, WriteTime only has a 
1042        resolution of 2 seconds. */
1043     ubuf->modtime &= ~1;
1044 }
1045
1046 int win_store_create_verifier(char *obj, createverf3 verf)
1047 {
1048     struct utimbuf ubuf;
1049
1050     win_verf_to_ubuf(&ubuf, verf);
1051     return win_utime_creation(obj, &ubuf, TRUE);
1052 }
1053
1054 int win_check_create_verifier(backend_statstruct * buf, createverf3 verf)
1055 {
1056     struct utimbuf ubuf;
1057
1058     win_verf_to_ubuf(&ubuf, verf);
1059     return (buf->st_ctime == ubuf.actime && buf->st_mtime == ubuf.modtime);
1060 }
1061
1062 #endif                                 /* WIN32 */