Merge "virtio-9p: enable the virtfs on Windows." into tizen
[sdk/emulator/qemu.git] / hw / 9pfs / virtio-9p-local-maru.c
1 /*
2  * Virtio 9p backend for Maru
3  * Based on hw/9pfs/virtio-9p-local.c:
4  *
5  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
6  *
7  * Contact:
8  *  Sooyoung Ha <yoosah.ha@samsung.com>
9  *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  *
25  * Contributors:
26  * - S-Core Co., Ltd
27  *
28  */
29
30 #include "hw/virtio/virtio.h"
31 #include "virtio-9p.h"
32 #ifndef CONFIG_WIN32
33 #include "virtio-9p-xattr.h"
34 #include <arpa/inet.h>
35 #include <pwd.h>
36 #include <grp.h>
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #include "qemu/xattr.h"
40 #endif
41 #include <libgen.h>
42 #ifdef CONFIG_LINUX
43 #include <linux/fs.h>
44 #endif
45 #ifdef CONFIG_LINUX_MAGIC_H
46 #include <linux/magic.h>
47 #endif
48 #ifndef CONFIG_WIN32
49 #include <sys/ioctl.h>
50 #endif
51
52 #include "../../tizen/src/debug_ch.h"
53 MULTI_DEBUG_CHANNEL(tizen, qemu_9p_local);
54
55 #ifndef XFS_SUPER_MAGIC
56 #define XFS_SUPER_MAGIC  0x58465342
57 #endif
58 #ifndef EXT2_SUPER_MAGIC
59 #define EXT2_SUPER_MAGIC 0xEF53
60 #endif
61 #ifndef REISERFS_SUPER_MAGIC
62 #define REISERFS_SUPER_MAGIC 0x52654973
63 #endif
64 #ifndef BTRFS_SUPER_MAGIC
65 #define BTRFS_SUPER_MAGIC 0x9123683E
66 #endif
67
68 #ifdef CONFIG_WIN32
69 #ifndef MSDOS_SUPER_MAGIC
70 #define MSDOS_SUPER_MAGIC 0x4d44
71 #endif
72 #ifndef NTFS_SUPER_MAGIC
73 #define NTFS_SUPER_MAGIC 0x5346544e
74 #endif
75
76 uint64_t hostBytesPerSector = -1;
77 #endif
78
79 #define VIRTFS_META_DIR ".virtfs_metadata"
80
81 #ifndef CONFIG_LINUX
82 #define AT_REMOVEDIR 0x200
83 #endif
84
85 static const char *local_mapped_attr_path(FsContext *ctx,
86                                           const char *path, char *buffer)
87 {
88     char *dir_name;
89     char *tmp_path = g_strdup(path);
90     char *base_name = basename(tmp_path);
91
92     /* NULL terminate the directory */
93     dir_name = tmp_path;
94     *(base_name - 1) = '\0';
95 #ifndef CONFIG_WIN32
96     snprintf(buffer, PATH_MAX, "%s/%s/%s/%s",
97              ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
98 #else
99     snprintf(buffer, PATH_MAX, "%s\\%s\\%s\\%s",
100              ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
101     while(buffer[strlen(buffer)-1] == '\\'){
102         buffer[strlen(buffer)-1] = '\0';
103     }
104 #endif
105     g_free(tmp_path);
106     return buffer;
107 }
108
109 static FILE *local_fopen(const char *path, const char *mode)
110 {
111     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
112     int fd;
113 #ifndef CONFIG_WIN32
114     int o_mode = 0;
115 #endif
116     FILE *fp;
117     int flags = O_NOFOLLOW;
118     /*
119      * only supports two modes
120      */
121     if (mode[0] == 'r') {
122         flags |= O_RDONLY;
123     } else if (mode[0] == 'w') {
124         flags |= O_WRONLY | O_TRUNC | O_CREAT;
125 #ifndef CONFIG_WIN32
126         o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
127 #endif
128     } else {
129         return NULL;
130     }
131 #ifndef CONFIG_WIN32
132     fd = open(path, flags, o_mode);
133 #else
134     fd = open(path, flags | O_BINARY);
135 #endif
136     if (fd == -1) {
137         return NULL;
138     }
139     fp = fdopen(fd, mode);
140     if (!fp) {
141         close(fd);
142     }
143     return fp;
144 }
145
146 #define ATTR_MAX 100
147 #ifndef CONFIG_WIN32
148 static void local_mapped_file_attr(FsContext *ctx, const char *path,
149                                    struct stat *stbuf)
150 {
151     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
152     FILE *fp;
153     char buf[ATTR_MAX];
154     char attr_path[PATH_MAX];
155
156     local_mapped_attr_path(ctx, path, attr_path);
157     fp = local_fopen(attr_path, "r");
158     if (!fp) {
159         return;
160     }
161     memset(buf, 0, ATTR_MAX);
162     while (fgets(buf, ATTR_MAX, fp)) {
163         if (!strncmp(buf, "virtfs.uid", 10)) {
164             stbuf->st_uid = atoi(buf+11);
165         } else if (!strncmp(buf, "virtfs.gid", 10)) {
166             stbuf->st_gid = atoi(buf+11);
167         } else if (!strncmp(buf, "virtfs.mode", 11)) {
168             stbuf->st_mode = atoi(buf+12);
169         } else if (!strncmp(buf, "virtfs.rdev", 11)) {
170             stbuf->st_rdev = atoi(buf+12);
171         }
172         memset(buf, 0, ATTR_MAX);
173     }
174     fclose(fp);
175 }
176 #endif
177
178 static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
179 {
180     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
181     int err;
182     char buffer[PATH_MAX];
183     char *path = fs_path->data;
184
185 #ifndef CONFIG_WIN32
186     err =  lstat(rpath(fs_ctx, path, buffer), stbuf);
187     if (err) {
188         return err;
189     }
190     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
191         /* Actual credentials are part of extended attrs */
192         uid_t tmp_uid;
193         gid_t tmp_gid;
194         mode_t tmp_mode;
195         dev_t tmp_dev;
196 #ifdef CONFIG_LINUX
197         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
198                     sizeof(uid_t)) > 0) {
199             stbuf->st_uid = tmp_uid;
200         }
201         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
202                     sizeof(gid_t)) > 0) {
203             stbuf->st_gid = tmp_gid;
204         }
205         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
206                     &tmp_mode, sizeof(mode_t)) > 0) {
207             stbuf->st_mode = tmp_mode;
208         }
209         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
210                     sizeof(dev_t)) > 0) {
211             stbuf->st_rdev = tmp_dev;
212         }
213 #else
214         /*
215          *  extra two parameters on Mac OS X.
216          *  first one is position which specifies an offset within the extended attribute.
217          *  i.e. extended attribute means "user.virtfs.uid". Currently, it is only used with
218          *  resource fork attribute and all other extended attributes, it is reserved and should be zero.
219          *  second one is options which specify option for retrieving extended attributes:
220          *  (XATTR_NOFOLLOW, XATTR_SHOWCOMPRESSION)
221          */
222         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
223                     sizeof(uid_t), 0, 0) > 0) {
224             stbuf->st_uid = tmp_uid;
225         }
226         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
227                     sizeof(gid_t), 0, 0) > 0) {
228             stbuf->st_gid = tmp_gid;
229         }
230         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
231                     &tmp_mode, sizeof(mode_t), 0, 0) > 0) {
232             stbuf->st_mode = tmp_mode;
233         }
234         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
235                     sizeof(dev_t), 0, 0) > 0) {
236             stbuf->st_rdev = tmp_dev;
237         }
238 #endif
239     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
240         local_mapped_file_attr(fs_ctx, path, stbuf);
241     }
242 #else
243     const char * pathname = rpath(fs_ctx, path, buffer);
244     if (hostBytesPerSector == -1) {
245         DWORD BytesPerSector;
246         TCHAR tmpName[PATH_MAX] = {0};
247
248         strncpy(tmpName, pathname, 3 > PATH_MAX ? PATH_MAX : 3);
249         tmpName[4 > PATH_MAX ? PATH_MAX : 4] = '\0';
250         LPCTSTR RootPathName = (LPCTSTR)tmpName;
251
252         GetDiskFreeSpace(RootPathName, NULL, &BytesPerSector, NULL, NULL);
253         hostBytesPerSector = BytesPerSector;
254     }
255     err = _stat(pathname, stbuf);
256
257     /* Modify the permission to 777 except the directories. */
258     stbuf->st_mode = stbuf->st_mode | 0777;
259 #endif
260     return err;
261 }
262
263 static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
264 {
265     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
266     int err;
267     char attr_dir[PATH_MAX];
268     char *tmp_path = g_strdup(path);
269 #ifndef CONFIG_WIN32
270     snprintf(attr_dir, PATH_MAX, "%s/%s/%s",
271              ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
272     err = mkdir(attr_dir, 0700);
273 #else
274     snprintf(attr_dir, PATH_MAX, "%s\\%s\\%s",
275              ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
276     err = mkdir(attr_dir);
277 #endif
278
279     if (err < 0 && errno == EEXIST) {
280         err = 0;
281     }
282     g_free(tmp_path);
283     return err;
284 }
285
286 static int local_set_mapped_file_attr(FsContext *ctx,
287                                       const char *path, FsCred *credp)
288 {
289     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
290     FILE *fp;
291     int ret = 0;
292     char buf[ATTR_MAX];
293     char attr_path[PATH_MAX];
294     int uid = -1, gid = -1, mode = -1, rdev = -1;
295
296     fp = local_fopen(local_mapped_attr_path(ctx, path, attr_path), "r");
297     if (!fp) {
298         goto create_map_file;
299     }
300     memset(buf, 0, ATTR_MAX);
301     while (fgets(buf, ATTR_MAX, fp)) {
302         if (!strncmp(buf, "virtfs.uid", 10)) {
303             uid = atoi(buf+11);
304         } else if (!strncmp(buf, "virtfs.gid", 10)) {
305             gid = atoi(buf+11);
306         } else if (!strncmp(buf, "virtfs.mode", 11)) {
307             mode = atoi(buf+12);
308         } else if (!strncmp(buf, "virtfs.rdev", 11)) {
309             rdev = atoi(buf+12);
310         }
311         memset(buf, 0, ATTR_MAX);
312     }
313     fclose(fp);
314     goto update_map_file;
315
316 create_map_file:
317     ret = local_create_mapped_attr_dir(ctx, path);
318     if (ret < 0) {
319         goto err_out;
320     }
321
322 update_map_file:
323     fp = local_fopen(attr_path, "w");
324     if (!fp) {
325         ret = -1;
326         goto err_out;
327     }
328
329     if (credp->fc_uid != -1) {
330         uid = credp->fc_uid;
331     }
332     if (credp->fc_gid != -1) {
333         gid = credp->fc_gid;
334     }
335     if (credp->fc_mode != -1) {
336         mode = credp->fc_mode;
337     }
338     if (credp->fc_rdev != -1) {
339         rdev = credp->fc_rdev;
340     }
341
342     if (uid != -1) {
343         fprintf(fp, "virtfs.uid=%d\n", uid);
344     }
345     if (gid != -1) {
346         fprintf(fp, "virtfs.gid=%d\n", gid);
347     }
348     if (mode != -1) {
349         fprintf(fp, "virtfs.mode=%d\n", mode);
350     }
351     if (rdev != -1) {
352         fprintf(fp, "virtfs.rdev=%d\n", rdev);
353     }
354     fclose(fp);
355
356 err_out:
357     return ret;
358 }
359
360 #ifndef CONFIG_WIN32
361 static int local_set_xattr(const char *path, FsCred *credp)
362 {
363     int err = 0;
364
365 #ifdef CONFIG_LINUX
366     if (credp->fc_uid != -1) {
367         err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
368                 0);
369         if (err) {
370             return err;
371         }
372     }
373     if (credp->fc_gid != -1) {
374         err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
375                 0);
376         if (err) {
377             return err;
378         }
379     }
380     if (credp->fc_mode != -1) {
381         err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
382                 sizeof(mode_t), 0);
383         if (err) {
384             return err;
385         }
386     }
387     if (credp->fc_rdev != -1) {
388         err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
389                 sizeof(dev_t), 0);
390         if (err) {
391             return err;
392         }
393     }
394 #else
395     /*
396      * In case of setxattr on OS X, position parameter has been added.
397      * Its purpose is the same as getxattr. Last parameter options is the same as flags on Linux.
398      * XATTR_NOFOLLOW / XATTR_CREATE / XATTR_REPLACE
399      */
400     if (credp->fc_uid != -1) {
401         err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
402                  0, 0);
403          if (err) {
404              return err;
405          }
406      }
407      if (credp->fc_gid != -1) {
408          err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
409                  0, 0);
410          if (err) {
411              return err;
412          }
413      }
414      if (credp->fc_mode != -1) {
415          err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
416                  sizeof(mode_t), 0, 0);
417          if (err) {
418              return err;
419          }
420      }
421      if (credp->fc_rdev != -1) {
422          err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
423                  sizeof(dev_t), 0, 0);
424          if (err) {
425              return err;
426          }
427      }
428 #endif
429
430     return 0;
431 }
432 #endif
433
434 static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
435                                          FsCred *credp)
436 {
437 #ifndef CONFIG_WIN32
438     char buffer[PATH_MAX];
439
440     if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
441                 credp->fc_gid) < 0) {
442         /*
443          * If we fail to change ownership and if we are
444          * using security model none. Ignore the error
445          */
446         if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
447             return -1;
448         }
449     }
450
451     if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
452         return -1;
453     }
454 #endif
455     return 0;
456 }
457
458 static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
459                               char *buf, size_t bufsz)
460 {
461     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
462     ssize_t tsize = -1;
463 #ifndef CONFIG_WIN32
464     char buffer[PATH_MAX];
465     char *path = fs_path->data;
466
467     if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
468         (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
469         int fd;
470         fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW);
471         if (fd == -1) {
472             return -1;
473         }
474         do {
475             tsize = read(fd, (void *)buf, bufsz);
476         } while (tsize == -1 && errno == EINTR);
477         close(fd);
478         return tsize;
479     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
480                (fs_ctx->export_flags & V9FS_SM_NONE)) {
481         tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
482     }
483 #endif
484     return tsize;
485 }
486
487 static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
488 {
489     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
490     return close(fs->fd);
491 }
492
493 static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
494 {
495     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
496     return closedir(fs->dir);
497 }
498
499 static int local_open(FsContext *ctx, V9fsPath *fs_path,
500                       int flags, V9fsFidOpenState *fs)
501 {
502     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
503     char buffer[PATH_MAX];
504     char *path = fs_path->data;
505 #ifdef CONFIG_WIN32
506     flags |= O_BINARY;
507 #endif
508
509     fs->fd = open(rpath(ctx, path, buffer), flags | O_NOFOLLOW);
510
511     return fs->fd;
512 }
513
514 static int local_opendir(FsContext *ctx,
515                          V9fsPath *fs_path, V9fsFidOpenState *fs)
516 {
517     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
518     char buffer[PATH_MAX];
519     char *path = fs_path->data;
520
521     fs->dir = opendir(rpath(ctx, path, buffer));
522     if (!fs->dir) {
523         return -1;
524     }
525     return 0;
526 }
527
528 static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
529 {
530     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
531     return rewinddir(fs->dir);
532 }
533
534 static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
535 {
536     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
537     return telldir(fs->dir);
538 }
539
540 static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
541                            struct dirent *entry,
542                            struct dirent **result)
543 {
544     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
545     int ret;
546
547 again:
548 #ifndef CONFIG_WIN32
549     ret = readdir_r(fs->dir, entry, result);
550     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
551         if (!ret && *result != NULL &&
552             !strcmp(entry->d_name, VIRTFS_META_DIR)) {
553             /* skp the meta data directory */
554             goto again;
555         }
556     }
557 #else
558     ret = errno;
559     *result = readdir(fs->dir);
560     ret = (ret == errno ? 0 : errno);
561     entry = *result;
562     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
563         if (!ret && *result != NULL &&
564             !strcmp(entry->d_name, VIRTFS_META_DIR)) {
565             /* skp the meta data directory */
566             goto again;
567         }
568     }
569 #endif
570     return ret;
571 }
572
573 static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
574 {
575     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
576     return seekdir(fs->dir, off);
577 }
578
579 static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
580                             const struct iovec *iov,
581                             int iovcnt, off_t offset)
582 {
583 #ifdef CONFIG_PREADV
584     return preadv(fs->fd, iov, iovcnt, offset);
585 #else
586     int err = lseek(fs->fd, offset, SEEK_SET);
587     if (err == -1) {
588         return err;
589     } else {
590         return readv(fs->fd, iov, iovcnt);
591     }
592 #endif
593 }
594
595 static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
596                              const struct iovec *iov,
597                              int iovcnt, off_t offset)
598 {
599     ssize_t ret;
600
601 #ifdef CONFIG_PREADV
602     ret = pwritev(fs->fd, iov, iovcnt, offset);
603 #else
604     int err = lseek(fs->fd, offset, SEEK_SET);
605     if (err == -1) {
606         return err;
607     } else {
608         ret = writev(fs->fd, iov, iovcnt);
609     }
610 #endif
611 #ifdef CONFIG_SYNC_FILE_RANGE
612     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
613         /*
614          * Initiate a writeback. This is not a data integrity sync.
615          * We want to ensure that we don't leave dirty pages in the cache
616          * after write when writeout=immediate is sepcified.
617          */
618         sync_file_range(fs->fd, offset, ret,
619                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
620     }
621 #endif
622     return ret;
623 }
624
625 static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
626 {
627     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
628 #ifndef CONFIG_WIN32
629     char buffer[PATH_MAX];
630     char *path = fs_path->data;
631
632     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
633         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
634     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
635         return local_set_mapped_file_attr(fs_ctx, path, credp);
636     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
637                (fs_ctx->export_flags & V9FS_SM_NONE)) {
638         return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
639     }
640 #endif
641     return -1;
642 }
643
644 static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
645                        const char *name, FsCred *credp)
646 {
647     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
648     int err = -1;
649 #ifndef CONFIG_WIN32
650     char *path;
651     int serrno = 0;
652     V9fsString fullname;
653     char buffer[PATH_MAX];
654
655     v9fs_string_init(&fullname);
656     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
657     path = fullname.data;
658
659     /* Determine the security model */
660     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
661         err = mknod(rpath(fs_ctx, path, buffer),
662                 SM_LOCAL_MODE_BITS|S_IFREG, 0);
663         if (err == -1) {
664             goto out;
665         }
666         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
667         if (err == -1) {
668             serrno = errno;
669             goto err_end;
670         }
671     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
672
673         err = mknod(rpath(fs_ctx, path, buffer),
674                     SM_LOCAL_MODE_BITS|S_IFREG, 0);
675         if (err == -1) {
676             goto out;
677         }
678         err = local_set_mapped_file_attr(fs_ctx, path, credp);
679         if (err == -1) {
680             serrno = errno;
681             goto err_end;
682         }
683     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
684                (fs_ctx->export_flags & V9FS_SM_NONE)) {
685         err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
686                 credp->fc_rdev);
687         if (err == -1) {
688             goto out;
689         }
690         err = local_post_create_passthrough(fs_ctx, path, credp);
691         if (err == -1) {
692             serrno = errno;
693             goto err_end;
694         }
695     }
696     goto out;
697
698 err_end:
699     remove(rpath(fs_ctx, path, buffer));
700     errno = serrno;
701 out:
702     v9fs_string_free(&fullname);
703 #endif
704     return err;
705 }
706
707 static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
708                        const char *name, FsCred *credp)
709 {
710     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
711     char *path;
712     int err = -1;
713     int serrno = 0;
714     V9fsString fullname;
715     char buffer[PATH_MAX];
716
717     v9fs_string_init(&fullname);
718 #ifndef CONFIG_WIN32
719     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
720 #else
721     v9fs_string_sprintf(&fullname, "%s\\%s", dir_path->data, name);
722     while((fullname.data)[strlen(fullname.data)-1] == '\\'){
723         (fullname.data)[strlen(fullname.data)-1] = '\0';
724     }
725 #endif
726     path = fullname.data;
727
728 #ifndef CONFIG_WIN32
729     /* Determine the security model */
730     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
731         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
732         if (err == -1) {
733             goto out;
734         }
735         credp->fc_mode = credp->fc_mode|S_IFDIR;
736         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
737         if (err == -1) {
738             serrno = errno;
739             goto err_end;
740         }
741     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
742         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
743         if (err == -1) {
744             goto out;
745         }
746         credp->fc_mode = credp->fc_mode|S_IFDIR;
747         err = local_set_mapped_file_attr(fs_ctx, path, credp);
748         if (err == -1) {
749             serrno = errno;
750             goto err_end;
751         }
752     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
753                (fs_ctx->export_flags & V9FS_SM_NONE)) {
754         err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
755         if (err == -1) {
756             goto out;
757         }
758         err = local_post_create_passthrough(fs_ctx, path, credp);
759         if (err == -1) {
760             serrno = errno;
761             goto err_end;
762         }
763     }
764 #else
765     err = mkdir(rpath(fs_ctx, path, buffer));
766 #endif
767     goto out;
768
769 err_end:
770     remove(rpath(fs_ctx, path, buffer));
771     errno = serrno;
772 out:
773     v9fs_string_free(&fullname);
774     return err;
775 }
776
777 static int local_fstat(FsContext *fs_ctx, int fid_type,
778                        V9fsFidOpenState *fs, struct stat *stbuf)
779 {
780     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
781     int err, fd;
782
783     if (fid_type == P9_FID_DIR) {
784 #ifndef CONFIG_WIN32
785         fd = dirfd(fs->dir);
786 #else
787         fd = fs->fd;
788 #endif
789     } else {
790         fd = fs->fd;
791     }
792
793     err = fstat(fd, stbuf);
794     if (err) {
795         return err;
796     }
797     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
798 #ifndef CONFIG_WIN32
799         /* Actual credentials are part of extended attrs */
800         uid_t tmp_uid;
801         gid_t tmp_gid;
802         mode_t tmp_mode;
803         dev_t tmp_dev;
804
805 #ifdef CONFIG_LINUX
806         if (fgetxattr(fd, "user.virtfs.uid",
807                       &tmp_uid, sizeof(uid_t)) > 0) {
808             stbuf->st_uid = tmp_uid;
809         }
810         if (fgetxattr(fd, "user.virtfs.gid",
811                       &tmp_gid, sizeof(gid_t)) > 0) {
812             stbuf->st_gid = tmp_gid;
813         }
814         if (fgetxattr(fd, "user.virtfs.mode",
815                       &tmp_mode, sizeof(mode_t)) > 0) {
816             stbuf->st_mode = tmp_mode;
817         }
818         if (fgetxattr(fd, "user.virtfs.rdev",
819                       &tmp_dev, sizeof(dev_t)) > 0) {
820                 stbuf->st_rdev = tmp_dev;
821         }
822 #else
823         if (fgetxattr(fd, "user.virtfs.uid",
824                       &tmp_uid, sizeof(uid_t), 0, 0) > 0) {
825             stbuf->st_uid = tmp_uid;
826         }
827         if (fgetxattr(fd, "user.virtfs.gid",
828                       &tmp_gid, sizeof(gid_t), 0, 0) > 0) {
829             stbuf->st_gid = tmp_gid;
830         }
831         if (fgetxattr(fd, "user.virtfs.mode",
832                       &tmp_mode, sizeof(mode_t), 0, 0) > 0) {
833             stbuf->st_mode = tmp_mode;
834         }
835         if (fgetxattr(fd, "user.virtfs.rdev",
836                       &tmp_dev, sizeof(dev_t), 0, 0) > 0) {
837                 stbuf->st_rdev = tmp_dev;
838         }
839 #endif
840 #endif
841     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
842         errno = EOPNOTSUPP;
843         return -1;
844     }
845     return err;
846 }
847
848 static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
849                        int flags, FsCred *credp, V9fsFidOpenState *fs)
850 {
851     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
852     char *path;
853     int fd = -1;
854     int err = -1;
855     int serrno = 0;
856     V9fsString fullname;
857     char buffer[PATH_MAX];
858
859     /*
860      * Mark all the open to not follow symlinks
861      */
862     flags |= O_NOFOLLOW;
863
864     v9fs_string_init(&fullname);
865 #ifndef CONFIG_WIN32
866     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
867 #else
868     v9fs_string_sprintf(&fullname, "%s\\%s", dir_path->data, name);
869     flags |= O_BINARY;
870 #endif
871     path = fullname.data;
872
873     /* Determine the security model */
874     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
875         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
876         if (fd == -1) {
877             err = fd;
878             goto out;
879         }
880 #ifndef CONFIG_WIN32
881         credp->fc_mode = credp->fc_mode|S_IFREG;
882         /* Set cleint credentials in xattr */
883         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
884         if (err == -1) {
885             serrno = errno;
886             goto err_end;
887         }
888 #endif
889     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
890         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
891         if (fd == -1) {
892             err = fd;
893             goto out;
894         }
895         credp->fc_mode = credp->fc_mode|S_IFREG;
896         /* Set client credentials in .virtfs_metadata directory files */
897         err = local_set_mapped_file_attr(fs_ctx, path, credp);
898         if (err == -1) {
899             serrno = errno;
900             goto err_end;
901         }
902     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
903                (fs_ctx->export_flags & V9FS_SM_NONE)) {
904         fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
905         if (fd == -1) {
906             err = fd;
907             goto out;
908         }
909         err = local_post_create_passthrough(fs_ctx, path, credp);
910         if (err == -1) {
911             serrno = errno;
912             goto err_end;
913         }
914     }
915     err = fd;
916     fs->fd = fd;
917     goto out;
918
919 err_end:
920     close(fd);
921     remove(rpath(fs_ctx, path, buffer));
922     errno = serrno;
923 out:
924     v9fs_string_free(&fullname);
925     return err;
926 }
927
928 static int local_symlink(FsContext *fs_ctx, const char *oldpath,
929                          V9fsPath *dir_path, const char *name, FsCred *credp)
930 {
931     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
932     int err = -1;
933 #ifndef CONFIG_WIN32
934     int serrno = 0;
935     char *newpath;
936     V9fsString fullname;
937     char buffer[PATH_MAX];
938
939     int flags = O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW;
940
941     v9fs_string_init(&fullname);
942     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
943     newpath = fullname.data;
944
945     /* Determine the security model */
946     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
947         int fd;
948         ssize_t oldpath_size, write_size;
949         fd = open(rpath(fs_ctx, newpath, buffer), flags, SM_LOCAL_MODE_BITS);
950         if (fd == -1) {
951             err = fd;
952             goto out;
953         }
954         /* Write the oldpath (target) to the file. */
955         oldpath_size = strlen(oldpath);
956         do {
957             write_size = write(fd, (void *)oldpath, oldpath_size);
958         } while (write_size == -1 && errno == EINTR);
959
960         if (write_size != oldpath_size) {
961             serrno = errno;
962             close(fd);
963             err = -1;
964             goto err_end;
965         }
966         close(fd);
967         /* Set cleint credentials in symlink's xattr */
968         credp->fc_mode = credp->fc_mode|S_IFLNK;
969         err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
970         if (err == -1) {
971             serrno = errno;
972             goto err_end;
973         }
974     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
975         int fd;
976         ssize_t oldpath_size, write_size;
977         fd = open(rpath(fs_ctx, newpath, buffer), flags, SM_LOCAL_MODE_BITS);
978         if (fd == -1) {
979             err = fd;
980             goto out;
981         }
982         /* Write the oldpath (target) to the file. */
983         oldpath_size = strlen(oldpath);
984         do {
985             write_size = write(fd, (void *)oldpath, oldpath_size);
986         } while (write_size == -1 && errno == EINTR);
987
988         if (write_size != oldpath_size) {
989             serrno = errno;
990             close(fd);
991             err = -1;
992             goto err_end;
993         }
994         close(fd);
995         /* Set cleint credentials in symlink's xattr */
996         credp->fc_mode = credp->fc_mode|S_IFLNK;
997         err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
998         if (err == -1) {
999             serrno = errno;
1000             goto err_end;
1001         }
1002     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
1003                (fs_ctx->export_flags & V9FS_SM_NONE)) {
1004         err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
1005         if (err) {
1006             goto out;
1007         }
1008         err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
1009                      credp->fc_gid);
1010         if (err == -1) {
1011             /*
1012              * If we fail to change ownership and if we are
1013              * using security model none. Ignore the error
1014              */
1015             if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
1016                 serrno = errno;
1017                 goto err_end;
1018             } else
1019                 err = 0;
1020         }
1021     }
1022     goto out;
1023
1024 err_end:
1025     remove(rpath(fs_ctx, newpath, buffer));
1026     errno = serrno;
1027 out:
1028     v9fs_string_free(&fullname);
1029 #endif
1030     return err;
1031 }
1032
1033 static int local_link(FsContext *ctx, V9fsPath *oldpath,
1034                       V9fsPath *dirpath, const char *name)
1035 {
1036     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1037     int ret = 0;
1038 #ifndef CONFIG_WIN32
1039     V9fsString newpath;
1040     char buffer[PATH_MAX], buffer1[PATH_MAX];
1041
1042     v9fs_string_init(&newpath);
1043     v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
1044
1045     ret = link(rpath(ctx, oldpath->data, buffer),
1046                rpath(ctx, newpath.data, buffer1));
1047
1048     /* now link the virtfs_metadata files */
1049     if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
1050         /* Link the .virtfs_metadata files. Create the metada directory */
1051         ret = local_create_mapped_attr_dir(ctx, newpath.data);
1052         if (ret < 0) {
1053             goto err_out;
1054         }
1055         ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer),
1056                    local_mapped_attr_path(ctx, newpath.data, buffer1));
1057         if (ret < 0 && errno != ENOENT) {
1058             goto err_out;
1059         }
1060     }
1061 err_out:
1062     v9fs_string_free(&newpath);
1063 #endif
1064     return ret;
1065 }
1066
1067 static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
1068 {
1069     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1070     char buffer[PATH_MAX];
1071     char *path = fs_path->data;
1072 #ifndef CONFIG_WIN32
1073     return truncate(rpath(ctx, path, buffer), size);
1074 #else
1075     int ret;
1076     int fd = open(rpath(ctx, path, buffer), O_RDWR | O_BINARY | O_NOFOLLOW);
1077     if(fd < 0) {
1078         ret = -1;
1079     } else {
1080         ret = ftruncate(fd, size);
1081         close(fd);
1082     }
1083     return ret;
1084 #endif
1085 }
1086
1087 static int local_rename(FsContext *ctx, const char *oldpath,
1088         const char *newpath)
1089 {
1090     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1091     int err;
1092     char buffer[PATH_MAX], buffer1[PATH_MAX];
1093
1094     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1095         err = local_create_mapped_attr_dir(ctx, newpath);
1096         if (err < 0) {
1097             return err;
1098         }
1099         /* rename the .virtfs_metadata files */
1100         err = rename(local_mapped_attr_path(ctx, oldpath, buffer),
1101                      local_mapped_attr_path(ctx, newpath, buffer1));
1102         if (err < 0 && errno != ENOENT) {
1103             return err;
1104         }
1105     }
1106 #ifndef CONFIG_WIN32
1107     return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
1108 #else
1109     if (!MoveFileEx((LPCTSTR)rpath(ctx, oldpath, buffer),
1110                     (LPCTSTR)rpath(ctx, newpath, buffer1), MOVEFILE_REPLACE_EXISTING)){
1111         err = -(GetLastError());
1112         ERR("[%d][ >> %s] err: %d\n", __LINE__, __func__, err);
1113     } else {
1114         err = 0;
1115     }
1116     return err;
1117 #endif
1118 }
1119
1120 static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
1121 {
1122     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1123 #ifndef CONFIG_WIN32
1124     char buffer[PATH_MAX];
1125     char *path = fs_path->data;
1126
1127     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
1128         (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
1129         (fs_ctx->export_flags & V9FS_SM_NONE)) {
1130         return lchown(rpath(fs_ctx, path, buffer),
1131                       credp->fc_uid, credp->fc_gid);
1132     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1133         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
1134     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1135         return local_set_mapped_file_attr(fs_ctx, path, credp);
1136     }
1137 #endif
1138     return -1;
1139 }
1140
1141 #ifdef CONFIG_WIN32
1142 /* The function that change file last access and modification times for WIN32 */
1143 static int win_utimes (const char *filename, const struct timeval tv[2])
1144 {
1145     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1146
1147     FILETIME LastAccessTime, LastWriteTime;
1148
1149     ULARGE_INTEGER tmpTime;
1150
1151     ULONGLONG WindowsUnixTimeGap = 11644473600; // between 1601.01.01 and 1970.01.01
1152     ULONGLONG WindowsSecond = 10000000; // 1sec / 100nanosec
1153
1154     int res = 0;
1155
1156     HANDLE hFile = CreateFile(filename, FILE_WRITE_ATTRIBUTES,
1157                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1158                             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
1159     if (hFile == INVALID_HANDLE_VALUE) {
1160         if (GetFileAttributes(filename) & FILE_ATTRIBUTE_DIRECTORY) {
1161             res = 0;
1162         }
1163         else {
1164             res = -1;
1165         }
1166     } else {
1167         if (!tv) { // case of NULL
1168             GetSystemTimeAsFileTime(&LastAccessTime);
1169             LastWriteTime = LastAccessTime;
1170         } else {
1171             tmpTime.QuadPart = UInt32x32To64(WindowsUnixTimeGap + tv[0].tv_sec, WindowsSecond)
1172                                + tv[0].tv_usec * 10;
1173             LastAccessTime.dwHighDateTime = tmpTime.HighPart;
1174             LastAccessTime.dwLowDateTime = tmpTime.LowPart;
1175
1176             tmpTime.QuadPart = UInt32x32To64(WindowsUnixTimeGap + tv[1].tv_sec, WindowsSecond)
1177                                + tv[1].tv_usec * 10;
1178             LastWriteTime.dwHighDateTime = tmpTime.HighPart;
1179             LastWriteTime.dwLowDateTime = tmpTime.LowPart;
1180         }
1181         if (!SetFileTime(hFile, NULL, &LastAccessTime, &LastWriteTime)) {
1182             res = -1;
1183         } else {
1184             res = 0;
1185         }
1186     }
1187
1188     if (hFile) {
1189         CloseHandle(hFile);
1190     }
1191     return res;
1192 }
1193 #endif
1194
1195 static int local_utimensat(FsContext *s, V9fsPath *fs_path,
1196                            const struct timespec *buf)
1197 {
1198     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1199     char buffer[PATH_MAX];
1200     char *path = fs_path->data;
1201 #ifndef CONFIG_WIN32
1202     return qemu_utimens(rpath(s, path, buffer), buf);
1203 #else
1204     const char * r_path = rpath(s, path, buffer);
1205     struct timeval tv[2], tv_now;
1206     struct stat st;
1207     int i;
1208
1209     /* happy if special cases */
1210     if (buf[0].tv_nsec == UTIME_OMIT && buf[1].tv_nsec == UTIME_OMIT) {
1211         return 0;
1212     }
1213     if (buf[0].tv_nsec == UTIME_NOW && buf[1].tv_nsec == UTIME_NOW) {
1214         return win_utimes(r_path, NULL);
1215     }
1216
1217     /* prepare for hard cases */
1218     if (buf[0].tv_nsec == UTIME_NOW || buf[1].tv_nsec == UTIME_NOW) {
1219         gettimeofday(&tv_now, NULL);
1220     }
1221     if (buf[0].tv_nsec == UTIME_OMIT || buf[1].tv_nsec == UTIME_OMIT) {
1222         _stat(r_path, &st);
1223     }
1224
1225     for (i = 0; i < 2; i++) {
1226         if (buf[i].tv_nsec == UTIME_NOW) {
1227             tv[i].tv_sec = tv_now.tv_sec;
1228             tv[i].tv_usec = tv_now.tv_usec;
1229         } else if (buf[i].tv_nsec == UTIME_OMIT) {
1230             tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime;
1231             tv[i].tv_usec = 0;
1232         } else {
1233             tv[i].tv_sec = buf[i].tv_sec;
1234             tv[i].tv_usec = buf[i].tv_nsec / 1000;
1235         }
1236     }
1237
1238     return win_utimes(r_path, &tv[0]);
1239 #endif
1240 }
1241
1242 static int local_remove(FsContext *ctx, const char *path)
1243 {
1244     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1245     int err;
1246     struct stat stbuf;
1247     char buffer[PATH_MAX];
1248
1249     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1250 #ifndef CONFIG_WIN32
1251         err =  lstat(rpath(ctx, path, buffer), &stbuf);
1252 #else
1253         err = _stat(rpath(ctx, path, buffer), &stbuf);
1254 #endif
1255         if (err) {
1256             goto err_out;
1257         }
1258         /*
1259          * If directory remove .virtfs_metadata contained in the
1260          * directory
1261          */
1262         if (S_ISDIR(stbuf.st_mode)) {
1263 #ifndef CONFIG_WIN32
1264             sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR);
1265 #else
1266             sprintf(buffer, "%s\\%s\\%s", ctx->fs_root, path, VIRTFS_META_DIR);
1267 #endif
1268             err = remove(buffer);
1269             if (err < 0 && errno != ENOENT) {
1270                 /*
1271                  * We didn't had the .virtfs_metadata file. May be file created
1272                  * in non-mapped mode ?. Ignore ENOENT.
1273                  */
1274                 goto err_out;
1275             }
1276         }
1277         /*
1278          * Now remove the name from parent directory
1279          * .virtfs_metadata directory
1280          */
1281         err = remove(local_mapped_attr_path(ctx, path, buffer));
1282         if (err < 0 && errno != ENOENT) {
1283             /*
1284              * We didn't had the .virtfs_metadata file. May be file created
1285              * in non-mapped mode ?. Ignore ENOENT.
1286              */
1287             goto err_out;
1288         }
1289     }
1290     return remove(rpath(ctx, path, buffer));
1291 err_out:
1292     return err;
1293 }
1294
1295 static int local_fsync(FsContext *ctx, int fid_type,
1296                        V9fsFidOpenState *fs, int datasync)
1297 {
1298     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1299     int fd;
1300
1301     if (fid_type == P9_FID_DIR) {
1302 #ifndef CONFIG_WIN32
1303         fd = dirfd(fs->dir);
1304 #else
1305         fd = fs->fd;
1306 #endif
1307     } else {
1308         fd = fs->fd;
1309     }
1310 #ifndef CONFIG_WIN32
1311     if (datasync) {
1312         return qemu_fdatasync(fd);
1313     } else {
1314         return fsync(fd);
1315     }
1316 #else
1317     return _commit(fd);
1318 #endif
1319 }
1320
1321 static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
1322 {
1323     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1324     char buffer[PATH_MAX];
1325     char *path = fs_path->data;
1326
1327 #ifndef CONFIG_WIN32
1328     return statfs(rpath(s, path, buffer), stbuf);
1329 #else
1330     DWORD VolumeSerialNumber,
1331           MaximumComponentLength,
1332           FileSystemFlags;
1333
1334     DWORD SectorsPerCluster,
1335           BytesPerSector,
1336           NumberOfFreeClusters,
1337           TotalNumberOfClusters,
1338           BytesPerCluster;
1339
1340     ULARGE_INTEGER TotalNumberOfBytes,
1341                    TotalNumberOfFreeBytes,
1342                    FreeBytesAvailableToCaller;
1343
1344     TCHAR tmpName[PATH_MAX] = {0};
1345     TCHAR VolumeNameBuffer[PATH_MAX] = {0};
1346     TCHAR FileSystemNameBuffer[PATH_MAX] = {0};
1347
1348     strncpy(tmpName, rpath(s, path, buffer), 3 > PATH_MAX ? PATH_MAX : 3);
1349     tmpName[4 > PATH_MAX ? PATH_MAX : 4] = '\0';
1350     LPCTSTR RootPathName = (LPCTSTR)tmpName;
1351
1352     if (RootPathName == NULL) {
1353         ERR("[%d][%s] >> err = %d\n", __LINE__, __func__, GetLastError());
1354         stbuf = NULL;
1355         return -1;
1356     }
1357
1358     if (!GetVolumeInformation(RootPathName, (LPTSTR)&VolumeNameBuffer, PATH_MAX,
1359                         &VolumeSerialNumber, &MaximumComponentLength, &FileSystemFlags,
1360                         (LPTSTR)&FileSystemNameBuffer, PATH_MAX)) {
1361         ERR("[%d][%s] >> err = %d\n", __LINE__, __func__, GetLastError());
1362         return -1;
1363     }
1364
1365     if (!GetDiskFreeSpace(RootPathName, &SectorsPerCluster, &BytesPerSector,
1366                         &NumberOfFreeClusters, &TotalNumberOfClusters)) {
1367         SectorsPerCluster = 1;
1368         BytesPerSector = 1;
1369         NumberOfFreeClusters = 0;
1370         TotalNumberOfClusters = 0;
1371     }
1372
1373     BytesPerCluster = SectorsPerCluster * BytesPerSector;
1374     TotalNumberOfBytes.QuadPart = Int32x32To64(TotalNumberOfClusters, BytesPerCluster);
1375     TotalNumberOfFreeBytes.QuadPart = Int32x32To64(NumberOfFreeClusters, BytesPerCluster);
1376     FreeBytesAvailableToCaller=TotalNumberOfFreeBytes;
1377
1378     if (!strcmp(FileSystemNameBuffer, "NTFS")) {
1379         stbuf->f_type = NTFS_SUPER_MAGIC;
1380     }
1381     /* need to check more about other filesystems (ex CD) */
1382     else {
1383         stbuf->f_type = MSDOS_SUPER_MAGIC;
1384     }
1385     stbuf->f_bsize       = BytesPerSector;
1386     stbuf->f_blocks      = TotalNumberOfBytes.QuadPart / BytesPerSector;
1387     stbuf->f_bfree       = TotalNumberOfFreeBytes.QuadPart / BytesPerSector;
1388     stbuf->f_bavail      = FreeBytesAvailableToCaller.QuadPart / BytesPerSector;
1389     stbuf->f_files       = stbuf->f_blocks / SectorsPerCluster;
1390     stbuf->f_ffree       = stbuf->f_bfree / SectorsPerCluster;
1391     stbuf->f_fsid.val[0] = HIWORD(VolumeSerialNumber);
1392     stbuf->f_fsid.val[1] = LOWORD(VolumeSerialNumber);
1393     stbuf->f_namelen     = MaximumComponentLength;
1394     stbuf->f_spare[0]    = 0;
1395     stbuf->f_spare[1]    = 0;
1396     stbuf->f_spare[2]    = 0;
1397     stbuf->f_spare[3]    = 0;
1398     stbuf->f_spare[4]    = 0;
1399     stbuf->f_spare[5]    = 0;
1400
1401     return 0;
1402 #endif
1403 }
1404
1405 static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
1406                                const char *name, void *value, size_t size)
1407 {
1408 #ifndef CONFIG_WIN32
1409     char *path = fs_path->data;
1410
1411     return v9fs_get_xattr(ctx, path, name, value, size);
1412 #else
1413     /* xattr doesn't support on Windows */
1414     return -1;
1415 #endif
1416 }
1417
1418 static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
1419                                 void *value, size_t size)
1420 {
1421 #ifndef CONFIG_WIN32
1422     char *path = fs_path->data;
1423
1424     return v9fs_list_xattr(ctx, path, value, size);
1425 #else
1426     /* xattr doesn't support on Windows */
1427     return -1;
1428 #endif
1429 }
1430
1431 static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
1432                            void *value, size_t size, int flags)
1433 {
1434 #ifndef CONFIG_WIN32
1435     char *path = fs_path->data;
1436
1437     return v9fs_set_xattr(ctx, path, name, value, size, flags);
1438 #else
1439     /* xattr doesn't support on Windows */
1440     return -1;
1441 #endif
1442 }
1443
1444 static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
1445                               const char *name)
1446 {
1447 #ifndef CONFIG_WIN32
1448     char *path = fs_path->data;
1449
1450     return v9fs_remove_xattr(ctx, path, name);
1451 #else
1452     /* xattr doesn't support on Windows */
1453     return -1;
1454 #endif
1455 }
1456
1457 static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
1458                               const char *name, V9fsPath *target)
1459 {
1460     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1461     if (dir_path) {
1462 #ifndef CONFIG_WIN32
1463         v9fs_string_sprintf((V9fsString *)target, "%s/%s",
1464                             dir_path->data, name);
1465 #else
1466         v9fs_string_sprintf((V9fsString *)target, "%s\\%s",
1467                             dir_path->data, name);
1468     while((target->data)[strlen(target->data)-1] == '\\'){
1469         (target->data)[strlen(target->data)-1] = '\0';
1470     }
1471 #endif
1472     } else {
1473         v9fs_string_sprintf((V9fsString *)target, "%s", name);
1474     }
1475     /* Bump the size for including terminating NULL */
1476     target->size++;
1477     return 0;
1478 }
1479
1480 static int local_renameat(FsContext *ctx, V9fsPath *olddir,
1481                           const char *old_name, V9fsPath *newdir,
1482                           const char *new_name)
1483 {
1484     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1485     int ret;
1486     V9fsString old_full_name, new_full_name;
1487
1488     v9fs_string_init(&old_full_name);
1489     v9fs_string_init(&new_full_name);
1490
1491 #ifndef CONFIG_WIN32
1492     v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
1493     v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
1494 #else
1495     v9fs_string_sprintf(&old_full_name, "%s\\%s", olddir->data, old_name);
1496     v9fs_string_sprintf(&new_full_name, "%s\\%s", newdir->data, new_name);
1497 #endif
1498
1499     ret = local_rename(ctx, old_full_name.data, new_full_name.data);
1500     v9fs_string_free(&old_full_name);
1501     v9fs_string_free(&new_full_name);
1502     return ret;
1503 }
1504
1505 static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
1506                           const char *name, int flags)
1507 {
1508     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1509     int ret;
1510     V9fsString fullname;
1511     char buffer[PATH_MAX];
1512
1513     v9fs_string_init(&fullname);
1514
1515 #ifndef CONFIG_WIN32
1516     v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
1517 #else
1518     v9fs_string_sprintf(&fullname, "%s\\%s", dir->data, name);
1519     while(fullname.data[strlen(fullname.data)-1] == '\\'){
1520         fullname.data[strlen(fullname.data)-1] = '\0';
1521     }
1522 #endif
1523     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1524 #ifdef CONFIG_VIRTFS_DARWIN
1525         // TODO: find something to replace AT_REMOVEDIR feature.
1526         if (flags == AT_REMOVEDIR) {
1527             /*
1528              * If directory remove .virtfs_metadata contained in the
1529              * directory
1530              */
1531 #ifndef CONFIG_WIN32
1532             sprintf(buffer, "%s/%s/%s", ctx->fs_root,
1533                     fullname.data, VIRTFS_META_DIR);
1534 #else
1535             sprintf(buffer, "%s\\%s\\%s", ctx->fs_root,
1536                     fullname.data, VIRTFS_META_DIR);
1537 #endif
1538             ret = remove(buffer);
1539             if (ret < 0 && errno != ENOENT) {
1540                 /*
1541                  * We didn't had the .virtfs_metadata file. May be file created
1542                  * in non-mapped mode ?. Ignore ENOENT.
1543                  */
1544                 goto err_out;
1545             }
1546         }
1547 #endif
1548         /*
1549          * Now remove the name from parent directory
1550          * .virtfs_metadata directory.
1551          */
1552         ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer));
1553         if (ret < 0 && errno != ENOENT) {
1554             /*
1555              * We didn't had the .virtfs_metadata file. May be file created
1556              * in non-mapped mode ?. Ignore ENOENT.
1557              */
1558             goto err_out;
1559         }
1560     }
1561     /* Remove the name finally */
1562 #ifndef CONFIG_WIN32
1563     ret = remove(rpath(ctx, fullname.data, buffer));
1564 #else
1565     if (flags == AT_REMOVEDIR) { // is dir
1566         ret = rmdir(rpath(ctx, fullname.data, buffer));
1567     } else { //is file
1568         ret = remove(rpath(ctx, fullname.data, buffer));
1569     }
1570 #endif
1571     v9fs_string_free(&fullname);
1572
1573 err_out:
1574     return ret;
1575 }
1576
1577 #ifndef CONFIG_WIN32
1578 static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
1579                                 mode_t st_mode, uint64_t *st_gen)
1580 {
1581     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1582     int err;
1583
1584 #ifdef FS_IOC_GETVERSION
1585     V9fsFidOpenState fid_open;
1586
1587     /*
1588      * Do not try to open special files like device nodes, fifos etc
1589      * We can get fd for regular files and directories only
1590      */
1591     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
1592             return 0;
1593     }
1594     err = local_open(ctx, path, O_RDONLY, &fid_open);
1595     if (err < 0) {
1596         return err;
1597     }
1598     err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
1599     local_close(ctx, &fid_open);
1600 #else
1601     err = -ENOTTY;
1602 #endif
1603     return err;
1604 }
1605 #endif
1606
1607 static int local_init(FsContext *ctx)
1608 {
1609     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1610     int err = 0;
1611 #ifdef FS_IOC_GETVERSION
1612     struct statfs stbuf;
1613 #endif
1614
1615 #ifndef CONFIG_WIN32
1616     if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
1617         ctx->xops = passthrough_xattr_ops;
1618     } else if (ctx->export_flags & V9FS_SM_MAPPED) {
1619         ctx->xops = mapped_xattr_ops;
1620     } else if (ctx->export_flags & V9FS_SM_NONE) {
1621         ctx->xops = none_xattr_ops;
1622     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1623         /*
1624          * xattr operation for mapped-file and passthrough
1625          * remain same.
1626          */
1627         ctx->xops = passthrough_xattr_ops;
1628     }
1629 #else
1630     ctx->xops = NULL;
1631 #endif
1632     ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
1633 #ifdef FS_IOC_GETVERSION
1634     /*
1635      * use ioc_getversion only if the iocl is definied
1636      */
1637     err = statfs(ctx->fs_root, &stbuf);
1638     if (!err) {
1639         switch (stbuf.f_type) {
1640         case EXT2_SUPER_MAGIC:
1641         case BTRFS_SUPER_MAGIC:
1642         case REISERFS_SUPER_MAGIC:
1643         case XFS_SUPER_MAGIC:
1644             ctx->exops.get_st_gen = local_ioc_getversion;
1645             break;
1646         }
1647     }
1648 #endif
1649     return err;
1650 }
1651
1652 static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
1653 {
1654     TRACE("[%d][ Enter >> %s]\n", __LINE__, __func__);
1655     const char *sec_model = qemu_opt_get(opts, "security_model");
1656     const char *path = qemu_opt_get(opts, "path");
1657
1658     if (!sec_model) {
1659         fprintf(stderr, "security model not specified, "
1660                 "local fs needs security model\nvalid options are:"
1661                 "\tsecurity_model=[passthrough|mapped|none]\n");
1662         return -1;
1663     }
1664
1665     if (!strcmp(sec_model, "passthrough")) {
1666         fse->export_flags |= V9FS_SM_PASSTHROUGH;
1667     } else if (!strcmp(sec_model, "mapped") ||
1668                !strcmp(sec_model, "mapped-xattr")) {
1669         fse->export_flags |= V9FS_SM_MAPPED;
1670     } else if (!strcmp(sec_model, "none")) {
1671         fse->export_flags |= V9FS_SM_NONE;
1672     } else if (!strcmp(sec_model, "mapped-file")) {
1673         fse->export_flags |= V9FS_SM_MAPPED_FILE;
1674     } else {
1675         fprintf(stderr, "Invalid security model %s specified, valid options are"
1676                 "\n\t [passthrough|mapped-xattr|mapped-file|none]\n",
1677                 sec_model);
1678         return -1;
1679     }
1680
1681     if (!path) {
1682         fprintf(stderr, "fsdev: No path specified.\n");
1683         return -1;
1684     }
1685     fse->path = g_strdup(path);
1686
1687     return 0;
1688 }
1689
1690 FileOperations local_ops = {
1691     .parse_opts = local_parse_opts,
1692     .init  = local_init,
1693     .lstat = local_lstat,
1694     .readlink = local_readlink,
1695     .close = local_close,
1696     .closedir = local_closedir,
1697     .open = local_open,
1698     .opendir = local_opendir,
1699     .rewinddir = local_rewinddir,
1700     .telldir = local_telldir,
1701     .readdir_r = local_readdir_r,
1702     .seekdir = local_seekdir,
1703     .statfs = local_statfs,
1704     .preadv = local_preadv,
1705     .pwritev = local_pwritev,
1706     .truncate = local_truncate,
1707     .utimensat = local_utimensat,
1708     .open2 = local_open2,
1709     .lgetxattr = local_lgetxattr,
1710     .llistxattr = local_llistxattr,
1711     .lsetxattr = local_lsetxattr,
1712     .lremovexattr = local_lremovexattr,
1713     .mkdir = local_mkdir,
1714     .symlink = local_symlink,
1715     .remove = local_remove,
1716     .fstat = local_fstat,
1717     .chmod = local_chmod,
1718     .mknod = local_mknod,
1719     .link = local_link,
1720     .rename = local_rename,
1721     .chown = local_chown,
1722     .fsync = local_fsync,
1723     .name_to_path = local_name_to_path,
1724     .unlinkat = local_unlinkat,
1725     .renameat  = local_renameat,
1726 };