From 8664337cc39c8575ccb60abb8c6e30f92828ea51 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 22 Sep 2014 10:27:21 +0100 Subject: [PATCH] New APIs: Implement stat calls that return nanosecond timestamps (RHBZ#1144891). The existing APIs guestfs_stat, guestfs_lstat and guestfs_lstatlist return a stat structure that contains atime, mtime and ctime fields that store only the timestamp in seconds. Modern filesystems can store timestamps down to nanosecond granularity, and the ordinary glibc stat(2) wrapper will return these in "hidden" stat fields: struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ with the following macros defined for backwards compatibility: #define st_atime st_atim.tv_sec #define st_mtime st_mtim.tv_sec #define st_ctime st_ctim.tv_sec It is not possible to redefine guestfs_stat to return a longer struct guestfs_stat with room for the extra nanosecond fields, because that would break the ABI of guestfs_lstatlist as it returns an array containing consecutive stat structs (not pointers). Changing the return type of guestfs_stat would break API. Changing the generator to support symbol versioning is judged to be too intrusive. Therefore this adds a new struct (guestfs_statns) and new APIs: guestfs_statns guestfs_lstatns guestfs_lstatnslist which return the new struct (or array of structs in the last case). The old APIs may of course still be used, forever, but are deprecated and shouldn't be used in new programs. Because virt tools are compiled with -DGUESTFS_WARN_DEPRECATED=1, I have updated all the places calling the deprecated functions. This has revealed some areas for improvement: in particular virt-diff and virt-ls could be changed to print the nanosecond fields. FUSE now returns nanoseconds in stat calls where available, fixing https://bugzilla.redhat.com/show_bug.cgi?id=1144891 Notes about the implementation: - guestfs_internal_lstatlist has been removed and replaced by guestfs_internal_lstatnslist. As the former was an internal API no one should have been calling it, or indeed can call it unless they start defining their own header files. - guestfs_stat and guestfs_lstat have been changed into library-side functions. They, along with guestfs_lstatlist, are now implemented as wrappers around the new functions which just throw away the nanosecond fields. --- TODO | 6 + cat/ls.c | 58 ++++---- cat/visit.c | 10 +- cat/visit.h | 2 +- configure.ac | 6 + daemon/stat.c | 168 ++++++++++------------- diff/diff.c | 119 ++++++++-------- fuse/test-fuse.c | 4 +- generator/actions.ml | 151 ++++++++++++-------- generator/structs.ml | 30 ++++ gobject/Makefile.inc | 2 + java/Makefile.inc | 1 + java/com/redhat/et/libguestfs/.gitignore | 1 + po/POTFILES | 1 + src/MAX_PROC_NR | 2 +- src/file.c | 91 ++++++++++-- src/fuse.c | 82 ++++++----- v2v/convert_linux.ml | 8 +- 18 files changed, 444 insertions(+), 298 deletions(-) diff --git a/TODO b/TODO index ea19795b7..e6af18636 100644 --- a/TODO +++ b/TODO @@ -598,3 +598,9 @@ Improvements in virt-log - Support Windows guests, see http://rwmj.wordpress.com/2011/04/17/decoding-the-windows-event-log-using-guestfish/ + +Subsecond handling in virt-diff, virt-ls +---------------------------------------- + +Handle nanoseconds properly. You should be able to specify them on +the command line and display them. diff --git a/cat/ls.c b/cat/ls.c index 43705c214..de8248e4f 100644 --- a/cat/ls.c +++ b/cat/ls.c @@ -71,7 +71,7 @@ static void output_int64 (int64_t); static void output_int64_dev (int64_t); static void output_int64_perms (int64_t); static void output_int64_size (int64_t); -static void output_int64_time (int64_t); +static void output_int64_time (int64_t secs, int64_t nsecs); static void output_int64_uid (int64_t); static void output_string (const char *); static void output_string_link (const char *); @@ -449,7 +449,7 @@ do_ls_R (const char *dir) return 0; } -static int show_file (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs, void *unused); +static int show_file (const char *dir, const char *name, const struct guestfs_statns *stat, const struct guestfs_xattr_list *xattrs, void *unused); static int do_ls_lR (const char *dir) @@ -466,7 +466,7 @@ do_ls_lR (const char *dir) */ static int show_file (const char *dir, const char *name, - const struct guestfs_stat *stat, + const struct guestfs_statns *stat, const struct guestfs_xattr_list *xattrs, void *unused) { @@ -476,45 +476,45 @@ show_file (const char *dir, const char *name, /* Display the basic fields. */ output_start_line (); - if (is_reg (stat->mode)) + if (is_reg (stat->st_mode)) filetype = "-"; - else if (is_dir (stat->mode)) + else if (is_dir (stat->st_mode)) filetype = "d"; - else if (is_chr (stat->mode)) + else if (is_chr (stat->st_mode)) filetype = "c"; - else if (is_blk (stat->mode)) + else if (is_blk (stat->st_mode)) filetype = "b"; - else if (is_fifo (stat->mode)) + else if (is_fifo (stat->st_mode)) filetype = "p"; - else if (is_lnk (stat->mode)) + else if (is_lnk (stat->st_mode)) filetype = "l"; - else if (is_sock (stat->mode)) + else if (is_sock (stat->st_mode)) filetype = "s"; else filetype = "u"; output_string (filetype); - output_int64_perms (stat->mode & 07777); + output_int64_perms (stat->st_mode & 07777); - output_int64_size (stat->size); + output_int64_size (stat->st_size); /* Display extra fields when enabled. */ if (enable_uids) { - output_int64_uid (stat->uid); - output_int64_uid (stat->gid); + output_int64_uid (stat->st_uid); + output_int64_uid (stat->st_gid); } if (enable_times) { - output_int64_time (stat->atime); - output_int64_time (stat->mtime); - output_int64_time (stat->ctime); + output_int64_time (stat->st_atime_sec, stat->st_atime_nsec); + output_int64_time (stat->st_mtime_sec, stat->st_mtime_nsec); + output_int64_time (stat->st_ctime_sec, stat->st_ctime_nsec); } if (enable_extra_stats) { - output_int64_dev (stat->dev); - output_int64 (stat->ino); - output_int64 (stat->nlink); - output_int64_dev (stat->rdev); - output_int64 (stat->blocks); + output_int64_dev (stat->st_dev); + output_int64 (stat->st_ino); + output_int64 (stat->st_nlink); + output_int64_dev (stat->st_rdev); + output_int64 (stat->st_blocks); } /* Disabled for now -- user would definitely want these to be interpreted. @@ -524,7 +524,7 @@ show_file (const char *dir, const char *name, path = full_path (dir, name); - if (checksum && is_reg (stat->mode)) { + if (checksum && is_reg (stat->st_mode)) { csum = guestfs_checksum (g, checksum, path); if (!csum) exit (EXIT_FAILURE); @@ -534,7 +534,7 @@ show_file (const char *dir, const char *name, output_string (path); - if (is_lnk (stat->mode)) + if (is_lnk (stat->st_mode)) /* XXX Fix this for NTFS. */ link = guestfs_readlink (g, path); if (link) @@ -703,7 +703,7 @@ output_int64_perms (int64_t i) } static void -output_int64_time (int64_t i) +output_int64_time (int64_t secs, int64_t nsecs) { int r; @@ -713,19 +713,19 @@ output_int64_time (int64_t i) if (time_t_output) { switch (time_relative) { case 0: /* --time-t */ - r = printf ("%10" PRIi64, i); + r = printf ("%10" PRIi64, secs); break; case 1: /* --time-relative */ - r = printf ("%8" PRIi64, now - i); + r = printf ("%8" PRIi64, now - secs); break; case 2: /* --time-days */ default: - r = printf ("%3" PRIi64, (now - i) / 86400); + r = printf ("%3" PRIi64, (now - secs) / 86400); break; } } else { - time_t t = (time_t) i; + time_t t = (time_t) secs; char buf[64]; struct tm *tm; diff --git a/cat/visit.c b/cat/visit.c index 2347b5672..963beb8d8 100644 --- a/cat/visit.c +++ b/cat/visit.c @@ -51,11 +51,11 @@ _visit (guestfs_h *g, int depth, const char *dir, * case. */ if (depth == 0) { - CLEANUP_FREE_STAT struct guestfs_stat *stat = NULL; + CLEANUP_FREE_STATNS struct guestfs_statns *stat = NULL; CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; int r; - stat = guestfs_lstat (g, dir); + stat = guestfs_lstatns (g, dir); if (stat == NULL) return -1; @@ -71,14 +71,14 @@ _visit (guestfs_h *g, int depth, const char *dir, size_t i, xattrp; CLEANUP_FREE_STRING_LIST char **names = NULL; - CLEANUP_FREE_STAT_LIST struct guestfs_stat_list *stats = NULL; + CLEANUP_FREE_STAT_LIST struct guestfs_statns_list *stats = NULL; CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; names = guestfs_ls (g, dir); if (names == NULL) return -1; - stats = guestfs_lstatlist (g, dir, names); + stats = guestfs_lstatnslist (g, dir, names); if (stats == NULL) return -1; @@ -123,7 +123,7 @@ _visit (guestfs_h *g, int depth, const char *dir, return -1; /* Recursively call visit, but only on directories. */ - if (is_dir (stats->val[i].mode)) { + if (is_dir (stats->val[i].st_mode)) { path = full_path (dir, names[i]); if (_visit (g, depth + 1, path, f, opaque) == -1) return -1; diff --git a/cat/visit.h b/cat/visit.h index f6b538b96..a64b42e54 100644 --- a/cat/visit.h +++ b/cat/visit.h @@ -19,7 +19,7 @@ #ifndef VISIT_H #define VISIT_H -typedef int (*visitor_function) (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs, void *opaque); +typedef int (*visitor_function) (const char *dir, const char *name, const struct guestfs_statns *stat, const struct guestfs_xattr_list *xattrs, void *opaque); extern int visit (guestfs_h *g, const char *dir, visitor_function f, void *opaque); diff --git a/configure.ac b/configure.ac index 0b2c0e01b..01f1b3bb5 100644 --- a/configure.ac +++ b/configure.ac @@ -270,6 +270,12 @@ dnl Check if stat has the required fields. AC_STRUCT_ST_BLOCKS AC_CHECK_MEMBER([struct stat.st_blksize],[ AC_DEFINE([HAVE_STRUCT_STAT_ST_BLKSIZE],[1],[Define to 1 if 'st_blksize' is a member of 'struct stat'.])]) +AC_CHECK_MEMBER([struct stat.st_atim.tv_nsec],[ + AC_DEFINE([HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC],[1],[Define to 1 if 'st_mtim.tv_nsec' is a member of 'struct stat'.])]) +AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],[ + AC_DEFINE([HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC],[1],[Define to 1 if 'st_mtim.tv_nsec' is a member of 'struct stat'.])]) +AC_CHECK_MEMBER([struct stat.st_ctim.tv_nsec],[ + AC_DEFINE([HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC],[1],[Define to 1 if 'st_mtim.tv_nsec' is a member of 'struct stat'.])]) dnl Define a C symbol for the host CPU architecture. AC_DEFINE_UNQUOTED([host_cpu],["$host_cpu"],[Host architecture.]) diff --git a/daemon/stat.c b/daemon/stat.c index 939fe08eb..a7849141e 100644 --- a/daemon/stat.c +++ b/daemon/stat.c @@ -30,11 +30,64 @@ #include "daemon.h" #include "actions.h" -guestfs_int_stat * -do_stat (const char *path) +static guestfs_int_statns * +stat_to_statns (guestfs_int_statns *ret, const struct stat *statbuf) +{ + if (ret == NULL) { + ret = malloc (sizeof *ret); + if (ret == NULL) { + reply_with_perror ("malloc"); + return NULL; + } + } + + ret->st_dev = statbuf->st_dev; + ret->st_ino = statbuf->st_ino; + ret->st_mode = statbuf->st_mode; + ret->st_nlink = statbuf->st_nlink; + ret->st_uid = statbuf->st_uid; + ret->st_gid = statbuf->st_gid; + ret->st_rdev = statbuf->st_rdev; + ret->st_size = statbuf->st_size; +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + ret->st_blksize = statbuf->st_blksize; +#else + ret->st_blksize = -1; +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + ret->st_blocks = statbuf->st_blocks; +#else + ret->st_blocks = -1; +#endif + ret->st_atime_sec = statbuf->st_atime; +#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC + ret->st_atime_nsec = statbuf->st_atim.tv_nsec; +#else + ret->st_atime_nsec = 0; +#endif + ret->st_mtime_sec = statbuf->st_mtime; +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + ret->st_mtime_nsec = statbuf->st_mtim.tv_nsec; +#else + ret->st_mtime_nsec = 0; +#endif + ret->st_ctime_sec = statbuf->st_ctime; +#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC + ret->st_ctime_nsec = statbuf->st_ctim.tv_nsec; +#else + ret->st_ctime_nsec = 0; +#endif + + ret->st_spare1 = ret->st_spare2 = ret->st_spare3 = + ret->st_spare4 = ret->st_spare5 = ret->st_spare6 = 0; + + return ret; +} + +guestfs_int_statns * +do_statns (const char *path) { int r; - guestfs_int_stat *ret; struct stat statbuf; CHROOT_IN; @@ -46,42 +99,13 @@ do_stat (const char *path) return NULL; } - ret = malloc (sizeof *ret); - if (ret == NULL) { - reply_with_perror ("malloc"); - return NULL; - } - - ret->dev = statbuf.st_dev; - ret->ino = statbuf.st_ino; - ret->mode = statbuf.st_mode; - ret->nlink = statbuf.st_nlink; - ret->uid = statbuf.st_uid; - ret->gid = statbuf.st_gid; - ret->rdev = statbuf.st_rdev; - ret->size = statbuf.st_size; -#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - ret->blksize = statbuf.st_blksize; -#else - ret->blksize = -1; -#endif -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - ret->blocks = statbuf.st_blocks; -#else - ret->blocks = -1; -#endif - ret->atime = statbuf.st_atime; - ret->mtime = statbuf.st_mtime; - ret->ctime = statbuf.st_ctime; - - return ret; + return stat_to_statns (NULL, &statbuf); } -guestfs_int_stat * -do_lstat (const char *path) +guestfs_int_statns * +do_lstatns (const char *path) { int r; - guestfs_int_stat *ret; struct stat statbuf; CHROOT_IN; @@ -93,42 +117,14 @@ do_lstat (const char *path) return NULL; } - ret = malloc (sizeof *ret); - if (ret == NULL) { - reply_with_perror ("malloc"); - return NULL; - } - - ret->dev = statbuf.st_dev; - ret->ino = statbuf.st_ino; - ret->mode = statbuf.st_mode; - ret->nlink = statbuf.st_nlink; - ret->uid = statbuf.st_uid; - ret->gid = statbuf.st_gid; - ret->rdev = statbuf.st_rdev; - ret->size = statbuf.st_size; -#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - ret->blksize = statbuf.st_blksize; -#else - ret->blksize = -1; -#endif -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - ret->blocks = statbuf.st_blocks; -#else - ret->blocks = -1; -#endif - ret->atime = statbuf.st_atime; - ret->mtime = statbuf.st_mtime; - ret->ctime = statbuf.st_ctime; - - return ret; + return stat_to_statns (NULL, &statbuf); } -guestfs_int_stat_list * -do_internal_lstatlist (const char *path, char *const *names) +guestfs_int_statns_list * +do_internal_lstatnslist (const char *path, char *const *names) { int path_fd; - guestfs_int_stat_list *ret; + guestfs_int_statns_list *ret; size_t i, nr_names; nr_names = count_strings (names); @@ -138,9 +134,10 @@ do_internal_lstatlist (const char *path, char *const *names) reply_with_perror ("malloc"); return NULL; } - ret->guestfs_int_stat_list_len = nr_names; - ret->guestfs_int_stat_list_val = calloc (nr_names, sizeof (guestfs_int_stat)); - if (ret->guestfs_int_stat_list_val == NULL) { + ret->guestfs_int_statns_list_len = nr_names; + ret->guestfs_int_statns_list_val = + calloc (nr_names, sizeof (guestfs_int_statns)); + if (ret->guestfs_int_statns_list_val == NULL) { reply_with_perror ("malloc"); free (ret); return NULL; @@ -152,7 +149,7 @@ do_internal_lstatlist (const char *path, char *const *names) if (path_fd == -1) { reply_with_perror ("%s", path); - free (ret->guestfs_int_stat_list_val); + free (ret->guestfs_int_statns_list_val); free (ret); return NULL; } @@ -163,35 +160,14 @@ do_internal_lstatlist (const char *path, char *const *names) r = fstatat (path_fd, names[i], &statbuf, AT_SYMLINK_NOFOLLOW); if (r == -1) - ret->guestfs_int_stat_list_val[i].ino = -1; - else { - ret->guestfs_int_stat_list_val[i].dev = statbuf.st_dev; - ret->guestfs_int_stat_list_val[i].ino = statbuf.st_ino; - ret->guestfs_int_stat_list_val[i].mode = statbuf.st_mode; - ret->guestfs_int_stat_list_val[i].nlink = statbuf.st_nlink; - ret->guestfs_int_stat_list_val[i].uid = statbuf.st_uid; - ret->guestfs_int_stat_list_val[i].gid = statbuf.st_gid; - ret->guestfs_int_stat_list_val[i].rdev = statbuf.st_rdev; - ret->guestfs_int_stat_list_val[i].size = statbuf.st_size; -#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - ret->guestfs_int_stat_list_val[i].blksize = statbuf.st_blksize; -#else - ret->guestfs_int_stat_list_val[i].blksize = -1; -#endif -#ifdef HAVE_STRUCT_STAT_ST_BLOCKS - ret->guestfs_int_stat_list_val[i].blocks = statbuf.st_blocks; -#else - ret->guestfs_int_stat_list_val[i].blocks = -1; -#endif - ret->guestfs_int_stat_list_val[i].atime = statbuf.st_atime; - ret->guestfs_int_stat_list_val[i].mtime = statbuf.st_mtime; - ret->guestfs_int_stat_list_val[i].ctime = statbuf.st_ctime; - } + ret->guestfs_int_statns_list_val[i].st_ino = -1; + else + stat_to_statns (&ret->guestfs_int_statns_list_val[i], &statbuf); } if (close (path_fd) == -1) { reply_with_perror ("close: %s", path); - free (ret->guestfs_int_stat_list_val); + free (ret->guestfs_int_statns_list_val); free (ret); return NULL; } diff --git a/diff/diff.c b/diff/diff.c index 16c970b97..af4e1797a 100644 --- a/diff/diff.c +++ b/diff/diff.c @@ -78,7 +78,7 @@ static void output_int64 (int64_t); static void output_int64_dev (int64_t); static void output_int64_perms (int64_t); static void output_int64_size (int64_t); -static void output_int64_time (int64_t); +static void output_int64_time (int64_t secs, int64_t nsecs); static void output_int64_uid (int64_t); static void output_string (const char *); static void output_string_link (const char *); @@ -398,7 +398,7 @@ struct tree { struct file { char *path; - struct guestfs_stat *stat; + struct guestfs_statns *stat; struct guestfs_xattr_list *xattrs; char *csum; /* Checksum. If NULL, use file times and size. */ }; @@ -410,7 +410,7 @@ free_tree (struct tree *t) for (i = 0; i < t->nr_files; ++i) { free (t->files[i].path); - guestfs_free_stat (t->files[i].stat); + guestfs_free_statns (t->files[i].stat); guestfs_free_xattr_list (t->files[i].xattrs); free (t->files[i].csum); } @@ -420,7 +420,7 @@ free_tree (struct tree *t) free (t); } -static int visit_entry (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs, void *vt); +static int visit_entry (const char *dir, const char *name, const struct guestfs_statns *stat, const struct guestfs_xattr_list *xattrs, void *vt); static struct tree * visit_guest (guestfs_h *g) @@ -454,13 +454,13 @@ visit_guest (guestfs_h *g) */ static int visit_entry (const char *dir, const char *name, - const struct guestfs_stat *stat_orig, + const struct guestfs_statns *stat_orig, const struct guestfs_xattr_list *xattrs_orig, void *vt) { struct tree *t = vt; char *path = NULL, *csum = NULL; - struct guestfs_stat *stat = NULL; + struct guestfs_statns *stat = NULL; struct guestfs_xattr_list *xattrs = NULL; size_t i; @@ -469,7 +469,7 @@ visit_entry (const char *dir, const char *name, /* Copy the stats and xattrs because the visit function will * free them after we return. */ - stat = guestfs_copy_stat (stat_orig); + stat = guestfs_copy_statns (stat_orig); if (stat == NULL) { perror ("guestfs_copy_stat"); goto error; @@ -480,7 +480,7 @@ visit_entry (const char *dir, const char *name, goto error; } - if (checksum && is_reg (stat->mode)) { + if (checksum && is_reg (stat->st_mode)) { csum = guestfs_checksum (t->g, checksum, path); if (!csum) goto error; @@ -488,19 +488,20 @@ visit_entry (const char *dir, const char *name, /* If --atime option was NOT passed, flatten the atime field. */ if (!atime) - stat->atime = 0; + stat->st_atime_sec = 0; /* If --dir-links option was NOT passed, flatten nlink field in * directories. */ - if (!dir_links && is_dir (stat->mode)) - stat->nlink = 0; + if (!dir_links && is_dir (stat->st_mode)) + stat->st_nlink = 0; /* If --dir-times option was NOT passed, flatten time fields in * directories. */ - if (!dir_times && is_dir (stat->mode)) - stat->atime = stat->mtime = stat->ctime = 0; + if (!dir_times && is_dir (stat->st_mode)) + stat->st_atime_sec = stat->st_mtime_sec = stat->st_ctime_sec = + stat->st_atime_nsec = stat->st_mtime_nsec = stat->st_ctime_nsec = 0; /* Add the pathname and stats to the list. */ i = t->nr_files++; @@ -535,7 +536,7 @@ visit_entry (const char *dir, const char *name, error: free (path); free (csum); - guestfs_free_stat (stat); + guestfs_free_statns (stat); guestfs_free_xattr_list (xattrs); return -1; } @@ -622,7 +623,7 @@ compare_stats (struct file *file1, struct file *file2) { int r; - r = guestfs_compare_stat (file1->stat, file2->stat); + r = guestfs_compare_statns (file1->stat, file2->stat); if (r != 0) return r; @@ -640,10 +641,10 @@ changed (guestfs_h *g1, struct file *file1, { /* Did file content change? */ if (cst != 0 || - (is_reg (file1->stat->mode) && is_reg (file2->stat->mode) && - (file1->stat->mtime != file2->stat->mtime || - file1->stat->ctime != file2->stat->ctime || - file1->stat->size != file2->stat->size))) { + (is_reg (file1->stat->st_mode) && is_reg (file2->stat->st_mode) && + (file1->stat->st_mtime_sec != file2->stat->st_mtime_sec || + file1->stat->st_ctime_sec != file2->stat->st_ctime_sec || + file1->stat->st_size != file2->stat->st_size))) { output_start_line (); output_string ("="); output_file (g1, file1); @@ -673,19 +674,19 @@ changed (guestfs_h *g1, struct file *file1, output_string ("changed:"); #define COMPARE_STAT(n) \ if (file1->stat->n != file2->stat->n) output_string (#n) - COMPARE_STAT (dev); - COMPARE_STAT (ino); - COMPARE_STAT (mode); - COMPARE_STAT (nlink); - COMPARE_STAT (uid); - COMPARE_STAT (gid); - COMPARE_STAT (rdev); - COMPARE_STAT (size); - COMPARE_STAT (blksize); - COMPARE_STAT (blocks); - COMPARE_STAT (atime); - COMPARE_STAT (mtime); - COMPARE_STAT (ctime); + COMPARE_STAT (st_dev); + COMPARE_STAT (st_ino); + COMPARE_STAT (st_mode); + COMPARE_STAT (st_nlink); + COMPARE_STAT (st_uid); + COMPARE_STAT (st_gid); + COMPARE_STAT (st_rdev); + COMPARE_STAT (st_size); + COMPARE_STAT (st_blksize); + COMPARE_STAT (st_blocks); + COMPARE_STAT (st_atime_sec); + COMPARE_STAT (st_mtime_sec); + COMPARE_STAT (st_ctime_sec); #undef COMPARE_STAT if (guestfs_compare_xattr_list (file1->xattrs, file2->xattrs)) output_string ("xattrs"); @@ -701,8 +702,8 @@ diff (struct file *file1, guestfs_h *g1, struct file *file2, guestfs_h *g2) CLEANUP_FREE char *tmpd, *tmpda = NULL, *tmpdb = NULL, *cmd = NULL; int r; - assert (is_reg (file1->stat->mode)); - assert (is_reg (file2->stat->mode)); + assert (is_reg (file1->stat->st_mode)); + assert (is_reg (file2->stat->st_mode)); if (asprintf (&tmpd, "%s/virtdiffXXXXXX", tmpdir) < 0) { perror ("asprintf"); @@ -755,47 +756,47 @@ output_file (guestfs_h *g, struct file *file) size_t i; CLEANUP_FREE char *link = NULL; - if (is_reg (file->stat->mode)) + if (is_reg (file->stat->st_mode)) filetype = "-"; - else if (is_dir (file->stat->mode)) + else if (is_dir (file->stat->st_mode)) filetype = "d"; - else if (is_chr (file->stat->mode)) + else if (is_chr (file->stat->st_mode)) filetype = "c"; - else if (is_blk (file->stat->mode)) + else if (is_blk (file->stat->st_mode)) filetype = "b"; - else if (is_fifo (file->stat->mode)) + else if (is_fifo (file->stat->st_mode)) filetype = "p"; - else if (is_lnk (file->stat->mode)) + else if (is_lnk (file->stat->st_mode)) filetype = "l"; - else if (is_sock (file->stat->mode)) + else if (is_sock (file->stat->st_mode)) filetype = "s"; else filetype = "u"; output_string (filetype); - output_int64_perms (file->stat->mode & 07777); + output_int64_perms (file->stat->st_mode & 07777); - output_int64_size (file->stat->size); + output_int64_size (file->stat->st_size); /* Display extra fields when enabled. */ if (enable_uids) { - output_int64_uid (file->stat->uid); - output_int64_uid (file->stat->gid); + output_int64_uid (file->stat->st_uid); + output_int64_uid (file->stat->st_gid); } if (enable_times) { if (atime) - output_int64_time (file->stat->atime); - output_int64_time (file->stat->mtime); - output_int64_time (file->stat->ctime); + output_int64_time (file->stat->st_atime_sec, file->stat->st_atime_nsec); + output_int64_time (file->stat->st_mtime_sec, file->stat->st_mtime_nsec); + output_int64_time (file->stat->st_ctime_sec, file->stat->st_ctime_nsec); } if (enable_extra_stats) { - output_int64_dev (file->stat->dev); - output_int64 (file->stat->ino); - output_int64 (file->stat->nlink); - output_int64_dev (file->stat->rdev); - output_int64 (file->stat->blocks); + output_int64_dev (file->stat->st_dev); + output_int64 (file->stat->st_ino); + output_int64 (file->stat->st_nlink); + output_int64_dev (file->stat->st_rdev); + output_int64 (file->stat->st_blocks); } if (file->csum) @@ -803,7 +804,7 @@ output_file (guestfs_h *g, struct file *file) output_string (file->path); - if (is_lnk (file->stat->mode)) { + if (is_lnk (file->stat->st_mode)) { /* XXX Fix this for NTFS. */ link = guestfs_readlink (g, file->path); if (link) @@ -1056,7 +1057,7 @@ output_int64_perms (int64_t i) } static void -output_int64_time (int64_t i) +output_int64_time (int64_t secs, int64_t nsecs) { int r; @@ -1066,19 +1067,19 @@ output_int64_time (int64_t i) if (time_t_output) { switch (time_relative) { case 0: /* --time-t */ - r = printf ("%10" PRIi64, i); + r = printf ("%10" PRIi64, secs); break; case 1: /* --time-relative */ - r = printf ("%8" PRIi64, now - i); + r = printf ("%8" PRIi64, now - secs); break; case 2: /* --time-days */ default: - r = printf ("%3" PRIi64, (now - i) / 86400); + r = printf ("%3" PRIi64, (now - secs) / 86400); break; } } else { - time_t t = (time_t) i; + time_t t = (time_t) secs; char buf[64]; struct tm *tm; diff --git a/fuse/test-fuse.c b/fuse/test-fuse.c index dda6fdeb3..2876dc4de 100644 --- a/fuse/test-fuse.c +++ b/fuse/test-fuse.c @@ -247,9 +247,9 @@ test_fuse (void) char buf[128]; ssize_t r; unsigned u, u1; -#if 0 int fd; struct timeval tv[2]; +#if 0 struct timespec ts[2]; #endif acl_t acl; @@ -544,7 +544,6 @@ test_fuse (void) return -1; } -#if 0 STAGE ("checking utimes"); fd = open ("timestamp", O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0644); @@ -574,7 +573,6 @@ test_fuse (void) (int) statbuf.st_mtime, (int) statbuf.st_mtim.tv_nsec); return -1; } -#endif #if 0 /* Does not work! See https://bugzilla.redhat.com/show_bug.cgi?id=1144766 */ diff --git a/generator/actions.ml b/generator/actions.ml index 73dcd33ec..778219828 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -2605,6 +2605,7 @@ See also C." }; { defaults with name = "lstatlist"; style = RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"], []; + deprecated_by = Some "lstatnslist"; shortdesc = "lstat on multiple files"; longdesc = "\ This call allows you to perform the C operation @@ -2613,7 +2614,26 @@ C is the list of files from this directory. On return you get a list of stat structs, with a one-to-one correspondence to the C list. If any name did not exist -or could not be lstat'd, then the C field of that structure +or could not be lstat'd, then the C field of that structure +is set to C<-1>. + +This call is intended for programs that want to efficiently +list a directory contents without making many round-trips. +See also C for a similarly efficient call +for getting extended attributes." }; + + { defaults with + name = "lstatnslist"; + style = RStructList ("statbufs", "statns"), [Pathname "path"; StringList "names"], []; + shortdesc = "lstat on multiple files"; + longdesc = "\ +This call allows you to perform the C operation +on multiple files, where all files are in the directory C. +C is the list of files from this directory. + +On return you get a list of stat structs, with a one-to-one +correspondence to the C list. If any name did not exist +or could not be lstat'd, then the C field of that structure is set to C<-1>. This call is intended for programs that want to efficiently @@ -3223,6 +3243,38 @@ This call returns the number of strings which were removed See L, L." }; + { defaults with + name = "stat"; + style = RStruct ("statbuf", "stat"), [Pathname "path"], []; + deprecated_by = Some "statns"; + tests = [ + InitISOFS, Always, TestResult ( + [["stat"; "/empty"]], "ret->size == 0"), [] + ]; + shortdesc = "get file information"; + longdesc = "\ +Returns file information for the given C. + +This is the same as the C system call." }; + + { defaults with + name = "lstat"; + style = RStruct ("statbuf", "stat"), [Pathname "path"], []; + deprecated_by = Some "lstatns"; + tests = [ + InitISOFS, Always, TestResult ( + [["lstat"; "/empty"]], "ret->size == 0"), [] + ]; + shortdesc = "get file information for a symbolic link"; + longdesc = "\ +Returns file information for the given C. + +This is the same as C except that if C +is a symbolic link, then the link is stat-ed, not the file it +refers to. + +This is the same as the C system call." }; + ] (* daemon_functions are any functions which cause some action @@ -4346,38 +4398,6 @@ result into a list of lines. See also: C" }; - { defaults with - name = "stat"; - style = RStruct ("statbuf", "stat"), [Pathname "path"], []; - proc_nr = Some 52; - tests = [ - InitISOFS, Always, TestResult ( - [["stat"; "/empty"]], "ret->size == 0"), [] - ]; - shortdesc = "get file information"; - longdesc = "\ -Returns file information for the given C. - -This is the same as the C system call." }; - - { defaults with - name = "lstat"; - style = RStruct ("statbuf", "stat"), [Pathname "path"], []; - proc_nr = Some 53; - tests = [ - InitISOFS, Always, TestResult ( - [["lstat"; "/empty"]], "ret->size == 0"), [] - ]; - shortdesc = "get file information for a symbolic link"; - longdesc = "\ -Returns file information for the given C. - -This is the same as C except that if C -is a symbolic link, then the link is stat-ed, not the file it -refers to. - -This is the same as the C system call." }; - { defaults with name = "statvfs"; style = RStruct ("statbuf", "statvfs"), [Pathname "path"], []; @@ -7492,30 +7512,6 @@ Only numeric uid and gid are supported. If you want to use names, you will need to locate and parse the password file yourself (Augeas support makes this relatively easy)." }; - { defaults with - name = "internal_lstatlist"; - style = RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"], []; - proc_nr = Some 204; - visibility = VInternal; - shortdesc = "lstat on multiple files"; - longdesc = "\ -This call allows you to perform the C operation -on multiple files, where all files are in the directory C. -C is the list of files from this directory. - -On return you get a list of stat structs, with a one-to-one -correspondence to the C list. If any name did not exist -or could not be lstat'd, then the C field of that structure -is set to C<-1>. - -This call is intended for programs that want to efficiently -list a directory contents without making many round-trips. -See also C for a similarly efficient call -for getting extended attributes. Very long directory listings -might cause the protocol message size to be exceeded, causing -this call to fail. The caller must split up such requests -into smaller groups of names." }; - { defaults with name = "internal_lxattrlist"; style = RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"], []; @@ -11942,6 +11938,47 @@ New (SVR4) portable format with a checksum. longdesc = "\ Get the realtime (wallclock) timestamp of the current journal entry." }; + { defaults with + name = "statns"; + style = RStruct ("statbuf", "statns"), [Pathname "path"], []; + proc_nr = Some 421; + tests = [ + InitISOFS, Always, TestResult ( + [["statns"; "/empty"]], "ret->st_size == 0"), [] + ]; + shortdesc = "get file information"; + longdesc = "\ +Returns file information for the given C. + +This is the same as the C system call." }; + + { defaults with + name = "lstatns"; + style = RStruct ("statbuf", "statns"), [Pathname "path"], []; + proc_nr = Some 422; + tests = [ + InitISOFS, Always, TestResult ( + [["lstatns"; "/empty"]], "ret->st_size == 0"), [] + ]; + shortdesc = "get file information for a symbolic link"; + longdesc = "\ +Returns file information for the given C. + +This is the same as C except that if C +is a symbolic link, then the link is stat-ed, not the file it +refers to. + +This is the same as the C system call." }; + + { defaults with + name = "internal_lstatnslist"; + style = RStructList ("statbufs", "statns"), [Pathname "path"; StringList "names"], []; + proc_nr = Some 423; + visibility = VInternal; + shortdesc = "lstat on multiple files"; + longdesc = "\ +This is the internal call which implements C." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/generator/structs.ml b/generator/structs.ml index 65c78b20e..578ebb79f 100644 --- a/generator/structs.ml +++ b/generator/structs.ml @@ -143,6 +143,36 @@ let structs = [ "ctime", FInt64; ]; s_camel_name = "Stat" }; + (* Because we omitted the nanosecond fields from the above struct, + * we also have this: + *) + { defaults with + s_name = "statns"; + s_cols = [ + "st_dev", FInt64; + "st_ino", FInt64; + "st_mode", FInt64; + "st_nlink", FInt64; + "st_uid", FInt64; + "st_gid", FInt64; + "st_rdev", FInt64; + "st_size", FInt64; + "st_blksize", FInt64; + "st_blocks", FInt64; + "st_atime_sec", FInt64; + "st_atime_nsec", FInt64; + "st_mtime_sec", FInt64; + "st_mtime_nsec", FInt64; + "st_ctime_sec", FInt64; + "st_ctime_nsec", FInt64; + "st_spare1", FInt64; + "st_spare2", FInt64; + "st_spare3", FInt64; + "st_spare4", FInt64; + "st_spare5", FInt64; + "st_spare6", FInt64; + ]; + s_camel_name = "StatNS" }; { defaults with s_name = "statvfs"; s_cols = [ diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index ed1ff3bc3..c93dace6c 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -38,6 +38,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/struct-mdstat.h \ include/guestfs-gobject/struct-partition.h \ include/guestfs-gobject/struct-stat.h \ + include/guestfs-gobject/struct-statns.h \ include/guestfs-gobject/struct-statvfs.h \ include/guestfs-gobject/struct-utsname.h \ include/guestfs-gobject/struct-version.h \ @@ -115,6 +116,7 @@ guestfs_gobject_sources= \ src/struct-mdstat.c \ src/struct-partition.c \ src/struct-stat.c \ + src/struct-statns.c \ src/struct-statvfs.c \ src/struct-utsname.c \ src/struct-version.c \ diff --git a/java/Makefile.inc b/java/Makefile.inc index 731e78210..614caaa5f 100644 --- a/java/Makefile.inc +++ b/java/Makefile.inc @@ -34,6 +34,7 @@ java_built_sources = \ com/redhat/et/libguestfs/PV.java \ com/redhat/et/libguestfs/Partition.java \ com/redhat/et/libguestfs/Stat.java \ + com/redhat/et/libguestfs/StatNS.java \ com/redhat/et/libguestfs/StatVFS.java \ com/redhat/et/libguestfs/UTSName.java \ com/redhat/et/libguestfs/VG.java \ diff --git a/java/com/redhat/et/libguestfs/.gitignore b/java/com/redhat/et/libguestfs/.gitignore index 00bcec968..4882c9672 100644 --- a/java/com/redhat/et/libguestfs/.gitignore +++ b/java/com/redhat/et/libguestfs/.gitignore @@ -12,6 +12,7 @@ MDStat.java PV.java Partition.java Stat.java +StatNS.java StatVFS.java UTSName.java VG.java diff --git a/po/POTFILES b/po/POTFILES index add74b635..aec8c62f8 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -238,6 +238,7 @@ gobject/src/struct-lvm_vg.c gobject/src/struct-mdstat.c gobject/src/struct-partition.c gobject/src/struct-stat.c +gobject/src/struct-statns.c gobject/src/struct-statvfs.c gobject/src/struct-utsname.c gobject/src/struct-version.c diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 816d01be5..572141363 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -420 +423 diff --git a/src/file.c b/src/file.c index d21a61d29..91f794763 100644 --- a/src/file.c +++ b/src/file.c @@ -377,33 +377,33 @@ guestfs__write_append (guestfs_h *g, const char *path, return write_or_append (g, path, content, size, 1); } -#define LSTATLIST_MAX 1000 +#define LSTATNSLIST_MAX 1000 -struct guestfs_stat_list * -guestfs__lstatlist (guestfs_h *g, const char *dir, char * const*names) +struct guestfs_statns_list * +guestfs__lstatnslist (guestfs_h *g, const char *dir, char * const*names) { size_t len = guestfs___count_strings (names); size_t old_len; - struct guestfs_stat_list *ret; + struct guestfs_statns_list *ret; ret = safe_malloc (g, sizeof *ret); ret->len = 0; ret->val = NULL; while (len > 0) { - CLEANUP_FREE_STAT_LIST struct guestfs_stat_list *stats = NULL; + CLEANUP_FREE_STATNS_LIST struct guestfs_statns_list *stats = NULL; /* Note we don't need to free up the strings because take_strings * does not do a deep copy. */ - CLEANUP_FREE char **first = take_strings (g, names, LSTATLIST_MAX, &names); + CLEANUP_FREE char **first = take_strings (g, names, LSTATNSLIST_MAX, &names); - len = len <= LSTATLIST_MAX ? 0 : len - LSTATLIST_MAX; + len = len <= LSTATNSLIST_MAX ? 0 : len - LSTATNSLIST_MAX; - stats = guestfs_internal_lstatlist (g, dir, first); + stats = guestfs_internal_lstatnslist (g, dir, first); if (stats == NULL) { - guestfs_free_stat_list (ret); + guestfs_free_statns_list (ret); return NULL; } @@ -411,9 +411,9 @@ guestfs__lstatlist (guestfs_h *g, const char *dir, char * const*names) old_len = ret->len; ret->len += stats->len; ret->val = safe_realloc (g, ret->val, - ret->len * sizeof (struct guestfs_stat)); + ret->len * sizeof (struct guestfs_statns)); memcpy (&ret->val[old_len], stats->val, - stats->len * sizeof (struct guestfs_stat)); + stats->len * sizeof (struct guestfs_statns)); } return ret; @@ -602,3 +602,72 @@ guestfs__ls (guestfs_h *g, const char *directory) close (fd); return NULL; } + +static void +statns_to_old_stat (struct guestfs_statns *a, struct guestfs_stat *r) +{ + r->dev = a->st_dev; + r->ino = a->st_ino; + r->mode = a->st_mode; + r->nlink = a->st_nlink; + r->uid = a->st_uid; + r->gid = a->st_gid; + r->rdev = a->st_rdev; + r->size = a->st_size; + r->blksize = a->st_blksize; + r->blocks = a->st_blocks; + r->atime = a->st_atime_sec; + r->mtime = a->st_mtime_sec; + r->ctime = a->st_ctime_sec; +} + +struct guestfs_stat * +guestfs__stat (guestfs_h *g, const char *path) +{ + CLEANUP_FREE_STATNS struct guestfs_statns *r; + struct guestfs_stat *ret; + + r = guestfs_statns (g, path); + if (r == NULL) + return NULL; + + ret = safe_malloc (g, sizeof *ret); + statns_to_old_stat (r, ret); + return ret; /* caller frees */ +} + +struct guestfs_stat * +guestfs__lstat (guestfs_h *g, const char *path) +{ + CLEANUP_FREE_STATNS struct guestfs_statns *r; + struct guestfs_stat *ret; + + r = guestfs_lstatns (g, path); + if (r == NULL) + return NULL; + + ret = safe_malloc (g, sizeof *ret); + statns_to_old_stat (r, ret); + return ret; /* caller frees */ +} + +struct guestfs_stat_list * +guestfs__lstatlist (guestfs_h *g, const char *dir, char * const*names) +{ + CLEANUP_FREE_STATNS_LIST struct guestfs_statns_list *r; + struct guestfs_stat_list *ret; + size_t i; + + r = guestfs_lstatnslist (g, dir, names); + if (r == NULL) + return NULL; + + ret = safe_malloc (g, sizeof *ret); + ret->len = r->len; + ret->val = safe_calloc (g, r->len, sizeof (struct guestfs_stat)); + + for (i = 0; i < r->len; ++i) + statns_to_old_stat (&r->val[i], &ret->val[i]); + + return ret; +} diff --git a/src/fuse.c b/src/fuse.c index 00f9092e9..08a8784e5 100644 --- a/src/fuse.c +++ b/src/fuse.c @@ -165,7 +165,7 @@ mount_local_readdir (const char *path, void *buf, fuse_fill_dir_t filler, */ names = malloc ((ents->len + 1) * sizeof (char *)); if (names) { - CLEANUP_FREE_STAT_LIST struct guestfs_stat_list *ss = NULL; + CLEANUP_FREE_STATNS_LIST struct guestfs_statns_list *ss = NULL; CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; char **links; @@ -173,26 +173,35 @@ mount_local_readdir (const char *path, void *buf, fuse_fill_dir_t filler, names[i] = ents->val[i].name; names[i] = NULL; - ss = guestfs_lstatlist (g, path, names); + ss = guestfs_lstatnslist (g, path, names); if (ss) { for (i = 0; i < ss->len; ++i) { - if (ss->val[i].ino >= 0) { + if (ss->val[i].st_ino >= 0) { struct stat statbuf; memset (&statbuf, 0, sizeof statbuf); - statbuf.st_dev = ss->val[i].dev; - statbuf.st_ino = ss->val[i].ino; - statbuf.st_mode = ss->val[i].mode; - statbuf.st_nlink = ss->val[i].nlink; - statbuf.st_uid = ss->val[i].uid; - statbuf.st_gid = ss->val[i].gid; - statbuf.st_rdev = ss->val[i].rdev; - statbuf.st_size = ss->val[i].size; - statbuf.st_blksize = ss->val[i].blksize; - statbuf.st_blocks = ss->val[i].blocks; - statbuf.st_atime = ss->val[i].atime; - statbuf.st_mtime = ss->val[i].mtime; - statbuf.st_ctime = ss->val[i].ctime; + statbuf.st_dev = ss->val[i].st_dev; + statbuf.st_ino = ss->val[i].st_ino; + statbuf.st_mode = ss->val[i].st_mode; + statbuf.st_nlink = ss->val[i].st_nlink; + statbuf.st_uid = ss->val[i].st_uid; + statbuf.st_gid = ss->val[i].st_gid; + statbuf.st_rdev = ss->val[i].st_rdev; + statbuf.st_size = ss->val[i].st_size; + statbuf.st_blksize = ss->val[i].st_blksize; + statbuf.st_blocks = ss->val[i].st_blocks; + statbuf.st_atime = ss->val[i].st_atime_sec; +#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC + statbuf.st_atim.tv_nsec = ss->val[i].st_atime_nsec; +#endif + statbuf.st_mtime = ss->val[i].st_mtime_sec; +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + statbuf.st_mtim.tv_nsec = ss->val[i].st_mtime_nsec; +#endif + statbuf.st_ctime = ss->val[i].st_ctime_sec; +#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC + statbuf.st_ctim.tv_nsec = ss->val[i].st_ctime_nsec; +#endif lsc_insert (g, path, names[i], now, &statbuf); } @@ -246,7 +255,7 @@ static int mount_local_getattr (const char *path, struct stat *statbuf) { const struct stat *buf; - CLEANUP_FREE_STAT struct guestfs_stat *r = NULL; + CLEANUP_FREE_STAT struct guestfs_statns *r = NULL; DECL_G (); DEBUG_CALL ("%s, %p", path, statbuf); @@ -256,24 +265,33 @@ mount_local_getattr (const char *path, struct stat *statbuf) return 0; } - r = guestfs_lstat (g, path); + r = guestfs_lstatns (g, path); if (r == NULL) RETURN_ERRNO; memset (statbuf, 0, sizeof *statbuf); - statbuf->st_dev = r->dev; - statbuf->st_ino = r->ino; - statbuf->st_mode = r->mode; - statbuf->st_nlink = r->nlink; - statbuf->st_uid = r->uid; - statbuf->st_gid = r->gid; - statbuf->st_rdev = r->rdev; - statbuf->st_size = r->size; - statbuf->st_blksize = r->blksize; - statbuf->st_blocks = r->blocks; - statbuf->st_atime = r->atime; - statbuf->st_mtime = r->mtime; - statbuf->st_ctime = r->ctime; + statbuf->st_dev = r->st_dev; + statbuf->st_ino = r->st_ino; + statbuf->st_mode = r->st_mode; + statbuf->st_nlink = r->st_nlink; + statbuf->st_uid = r->st_uid; + statbuf->st_gid = r->st_gid; + statbuf->st_rdev = r->st_rdev; + statbuf->st_size = r->st_size; + statbuf->st_blksize = r->st_blksize; + statbuf->st_blocks = r->st_blocks; + statbuf->st_atime = r->st_atime_sec; +#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC + statbuf->st_atim.tv_nsec = r->st_atime_nsec; +#endif + statbuf->st_mtime = r->st_mtime_sec; +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + statbuf->st_mtim.tv_nsec = r->st_mtime_nsec; +#endif + statbuf->st_ctime = r->st_ctime_sec; +#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC + statbuf->st_ctim.tv_nsec = r->st_ctime_nsec; +#endif return 0; } @@ -1133,7 +1151,7 @@ guestfs__umount_local (guestfs_h *g, * Note on attribute caching: FUSE can cache filesystem attributes for * short periods of time (configurable via -o attr_timeout). It * doesn't cache xattrs, and in any case FUSE caching doesn't solve - * the problem that we have to make a series of guestfs_lstat and + * the problem that we have to make a series of guestfs_lstatns and * guestfs_lgetxattr calls when we first list a directory (thus, many * round trips). * diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml index fb254b17a..d932bcc11 100644 --- a/v2v/convert_linux.ml +++ b/v2v/convert_linux.ml @@ -43,7 +43,7 @@ type kernel_info = { ki_version : string; (* version-release *) ki_arch : string; (* Kernel architecture. *) ki_vmlinuz : string; (* The path of the vmlinuz file. *) - ki_vmlinuz_stat : G.stat; (* stat(2) of vmlinuz *) + ki_vmlinuz_stat : G.statns; (* stat(2) of vmlinuz *) ki_initrd : string option; (* Path of initramfs, if found. *) ki_modpath : string; (* The module path. *) ki_modules : string list; (* The list of module names. *) @@ -165,7 +165,7 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = if not (g#is_dir ~followsymlinks:true modpath) then raise Not_found; let vmlinuz_stat = - try g#stat vmlinuz with G.Error _ -> raise Not_found in + try g#statns vmlinuz with G.Error _ -> raise Not_found in (* Get/construct the version. XXX Read this from kernel file. *) let version = @@ -357,11 +357,11 @@ let rec convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source = filter_map ( fun vmlinuz -> try - let statbuf = g#stat vmlinuz in + let statbuf = g#statns vmlinuz in let kernel = List.find ( fun { ki_vmlinuz_stat = s } -> - statbuf.G.dev = s.G.dev && statbuf.G.ino = s.G.ino + statbuf.G.st_dev = s.G.st_dev && statbuf.G.st_ino = s.G.st_ino ) installed_kernels in Some kernel with Not_found -> None