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