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