Generated code for stat/lstat/statvfs changes.
authorRichard Jones <rjones@redhat.com>
Wed, 15 Apr 2009 09:45:01 +0000 (10:45 +0100)
committerRichard Jones <rjones@redhat.com>
Wed, 15 Apr 2009 09:45:01 +0000 (10:45 +0100)
20 files changed:
daemon/actions.h
daemon/stubs.c
fish/cmds.c
fish/completion.c
guestfish-actions.pod
guestfs-actions.pod
ocaml/guestfs.ml
ocaml/guestfs.mli
ocaml/guestfs_c_actions.c
perl/Guestfs.xs
perl/lib/Sys/Guestfs.pm
python/guestfs-py.c
python/guestfs.py
src/guestfs-actions.c
src/guestfs-actions.h
src/guestfs-structs.h
src/guestfs_protocol.c
src/guestfs_protocol.h
src/guestfs_protocol.x
tests.c

index 90aeb8d..c0f41ce 100644 (file)
@@ -72,3 +72,6 @@ extern int do_lvm_remove_all (void);
 extern char *do_file (const char *path);
 extern char *do_command (char * const* const arguments);
 extern char **do_command_lines (char * const* const arguments);
+extern guestfs_int_stat *do_stat (const char *path);
+extern guestfs_int_stat *do_lstat (const char *path);
+extern guestfs_int_statvfs *do_statvfs (const char *path);
index 9a0dc91..9662de8 100644 (file)
@@ -1223,6 +1223,87 @@ done:
   xdr_free ((xdrproc_t) xdr_guestfs_command_lines_args, (char *) &args);
 }
 
+static void stat_stub (XDR *xdr_in)
+{
+  guestfs_int_stat *r;
+  struct guestfs_stat_args args;
+  const char *path;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_stat_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "stat");
+    return;
+  }
+  path = args.path;
+
+  r = do_stat (path);
+  if (r == NULL)
+    /* do_stat has already called reply_with_error */
+    goto done;
+
+  struct guestfs_stat_ret ret;
+  ret.statbuf = *r;
+  reply ((xdrproc_t) xdr_guestfs_stat_ret, (char *) &ret);
+  xdr_free ((xdrproc_t) xdr_guestfs_stat_ret, (char *) &ret);
+done:
+  xdr_free ((xdrproc_t) xdr_guestfs_stat_args, (char *) &args);
+}
+
+static void lstat_stub (XDR *xdr_in)
+{
+  guestfs_int_stat *r;
+  struct guestfs_lstat_args args;
+  const char *path;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_lstat_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "lstat");
+    return;
+  }
+  path = args.path;
+
+  r = do_lstat (path);
+  if (r == NULL)
+    /* do_lstat has already called reply_with_error */
+    goto done;
+
+  struct guestfs_lstat_ret ret;
+  ret.statbuf = *r;
+  reply ((xdrproc_t) xdr_guestfs_lstat_ret, (char *) &ret);
+  xdr_free ((xdrproc_t) xdr_guestfs_lstat_ret, (char *) &ret);
+done:
+  xdr_free ((xdrproc_t) xdr_guestfs_lstat_args, (char *) &args);
+}
+
+static void statvfs_stub (XDR *xdr_in)
+{
+  guestfs_int_statvfs *r;
+  struct guestfs_statvfs_args args;
+  const char *path;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_statvfs_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "statvfs");
+    return;
+  }
+  path = args.path;
+
+  r = do_statvfs (path);
+  if (r == NULL)
+    /* do_statvfs has already called reply_with_error */
+    goto done;
+
+  struct guestfs_statvfs_ret ret;
+  ret.statbuf = *r;
+  reply ((xdrproc_t) xdr_guestfs_statvfs_ret, (char *) &ret);
+  xdr_free ((xdrproc_t) xdr_guestfs_statvfs_ret, (char *) &ret);
+done:
+  xdr_free ((xdrproc_t) xdr_guestfs_statvfs_args, (char *) &args);
+}
+
 void dispatch_incoming_message (XDR *xdr_in)
 {
   switch (proc_nr) {
@@ -1379,6 +1460,15 @@ void dispatch_incoming_message (XDR *xdr_in)
     case GUESTFS_PROC_COMMAND_LINES:
       command_lines_stub (xdr_in);
       break;
+    case GUESTFS_PROC_STAT:
+      stat_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_LSTAT:
+      lstat_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_STATVFS:
+      statvfs_stub (xdr_in);
+      break;
     default:
       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
   }
index b658614..60aee8c 100644 (file)
@@ -65,6 +65,7 @@ void list_commands (void)
   printf ("%-20s %s\n", "list-partitions", "list the partitions");
   printf ("%-20s %s\n", "ll", "list the files in a directory (long format)");
   printf ("%-20s %s\n", "ls", "list the files in a directory");
+  printf ("%-20s %s\n", "lstat", "get file information for a symbolic link");
   printf ("%-20s %s\n", "lvcreate", "create an LVM volume group");
   printf ("%-20s %s\n", "lvm-remove-all", "remove all LVM LVs, VGs and PVs");
   printf ("%-20s %s\n", "lvs", "list the LVM logical volumes (LVs)");
@@ -85,6 +86,8 @@ void list_commands (void)
   printf ("%-20s %s\n", "set-path", "set the search path");
   printf ("%-20s %s\n", "set-verbose", "set verbose mode");
   printf ("%-20s %s\n", "sfdisk", "create partitions on a block device");
+  printf ("%-20s %s\n", "stat", "get file information");
+  printf ("%-20s %s\n", "statvfs", "get file system statistics");
   printf ("%-20s %s\n", "sync", "sync disks, writes are flushed through to the disk image");
   printf ("%-20s %s\n", "touch", "update file timestamps or create a new file");
   printf ("%-20s %s\n", "umount", "unmount a filesystem");
@@ -284,6 +287,15 @@ void display_command (const char *cmd)
   if (strcasecmp (cmd, "command_lines") == 0 || strcasecmp (cmd, "command-lines") == 0)
     pod2text ("command-lines - run a command, returning lines", " command-lines <arguments>\n\nThis is the same as C<command>, but splits the\nresult into a list of lines.");
   else
+  if (strcasecmp (cmd, "stat") == 0)
+    pod2text ("stat - get file information", " stat <path>\n\nReturns file information for the given C<path>.\n\nThis is the same as the C<stat(2)> system call.");
+  else
+  if (strcasecmp (cmd, "lstat") == 0)
+    pod2text ("lstat - get file information for a symbolic link", " lstat <path>\n\nReturns file information for the given C<path>.\n\nThis is the same as C<stat> except that if C<path>\nis a symbolic link, then the link is stat-ed, not the file it\nrefers to.\n\nThis is the same as the C<lstat(2)> system call.");
+  else
+  if (strcasecmp (cmd, "statvfs") == 0)
+    pod2text ("statvfs - get file system statistics", " statvfs <path>\n\nReturns file system statistics for any mounted file system.\nC<path> should be a file or directory in the mounted file system\n(typically it is the mount point itself, but it doesn't need to be).\n\nThis is the same as the C<statvfs(2)> system call.");
+  else
     display_builtin_command (cmd);
 }
 
@@ -389,6 +401,38 @@ static void print_lv_list (struct guestfs_lvm_lv_list *lvs)
     print_lv (&lvs->val[i]);
 }
 
+static void print_stat (struct guestfs_stat *stat)
+{
+  printf ("dev: %" PRIi64 "\n", stat->dev);
+  printf ("ino: %" PRIi64 "\n", stat->ino);
+  printf ("mode: %" PRIi64 "\n", stat->mode);
+  printf ("nlink: %" PRIi64 "\n", stat->nlink);
+  printf ("uid: %" PRIi64 "\n", stat->uid);
+  printf ("gid: %" PRIi64 "\n", stat->gid);
+  printf ("rdev: %" PRIi64 "\n", stat->rdev);
+  printf ("size: %" PRIi64 "\n", stat->size);
+  printf ("blksize: %" PRIi64 "\n", stat->blksize);
+  printf ("blocks: %" PRIi64 "\n", stat->blocks);
+  printf ("atime: %" PRIi64 "\n", stat->atime);
+  printf ("mtime: %" PRIi64 "\n", stat->mtime);
+  printf ("ctime: %" PRIi64 "\n", stat->ctime);
+}
+
+static void print_statvfs (struct guestfs_statvfs *statvfs)
+{
+  printf ("bsize: %" PRIi64 "\n", statvfs->bsize);
+  printf ("frsize: %" PRIi64 "\n", statvfs->frsize);
+  printf ("blocks: %" PRIi64 "\n", statvfs->blocks);
+  printf ("bfree: %" PRIi64 "\n", statvfs->bfree);
+  printf ("bavail: %" PRIi64 "\n", statvfs->bavail);
+  printf ("files: %" PRIi64 "\n", statvfs->files);
+  printf ("ffree: %" PRIi64 "\n", statvfs->ffree);
+  printf ("favail: %" PRIi64 "\n", statvfs->favail);
+  printf ("fsid: %" PRIi64 "\n", statvfs->fsid);
+  printf ("flag: %" PRIi64 "\n", statvfs->flag);
+  printf ("namemax: %" PRIi64 "\n", statvfs->namemax);
+}
+
 static int run_launch (const char *cmd, int argc, char *argv[])
 {
   int r;
@@ -1340,6 +1384,57 @@ static int run_command_lines (const char *cmd, int argc, char *argv[])
   return 0;
 }
 
+static int run_stat (const char *cmd, int argc, char *argv[])
+{
+  struct guestfs_stat *r;
+  const char *path;
+  if (argc != 1) {
+    fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  r = guestfs_stat (g, path);
+  if (r == NULL) return -1;
+  print_stat (r);
+  free (r);
+  return 0;
+}
+
+static int run_lstat (const char *cmd, int argc, char *argv[])
+{
+  struct guestfs_stat *r;
+  const char *path;
+  if (argc != 1) {
+    fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  r = guestfs_lstat (g, path);
+  if (r == NULL) return -1;
+  print_stat (r);
+  free (r);
+  return 0;
+}
+
+static int run_statvfs (const char *cmd, int argc, char *argv[])
+{
+  struct guestfs_statvfs *r;
+  const char *path;
+  if (argc != 1) {
+    fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  path = argv[0];
+  r = guestfs_statvfs (g, path);
+  if (r == NULL) return -1;
+  print_statvfs (r);
+  free (r);
+  return 0;
+}
+
 int run_action (const char *cmd, int argc, char *argv[])
 {
   if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
@@ -1528,6 +1623,15 @@ int run_action (const char *cmd, int argc, char *argv[])
   if (strcasecmp (cmd, "command_lines") == 0 || strcasecmp (cmd, "command-lines") == 0)
     return run_command_lines (cmd, argc, argv);
   else
+  if (strcasecmp (cmd, "stat") == 0)
+    return run_stat (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "lstat") == 0)
+    return run_lstat (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "statvfs") == 0)
+    return run_statvfs (cmd, argc, argv);
+  else
     {
       fprintf (stderr, "%s: unknown command\n", cmd);
       return -1;
index 150b1aa..7b4f818 100644 (file)
@@ -71,6 +71,7 @@ static const char *commands[] = {
   "list-partitions",
   "ll",
   "ls",
+  "lstat",
   "lvcreate",
   "lvm-remove-all",
   "lvs",
@@ -93,6 +94,8 @@ static const char *commands[] = {
   "set-path",
   "set-verbose",
   "sfdisk",
+  "stat",
+  "statvfs",
   "sync",
   "touch",
   "umount",
index fbf2f97..e240f49 100644 (file)
@@ -377,6 +377,18 @@ hidden files are shown.
 This command is mostly useful for interactive sessions.  Programs
 should probably use C<readdir> instead.
 
+=head2 lstat
+
+ lstat path
+
+Returns file information for the given C<path>.
+
+This is the same as C<stat> except that if C<path>
+is a symbolic link, then the link is stat-ed, not the file it
+refers to.
+
+This is the same as the C<lstat(2)> system call.
+
 =head2 lvcreate
 
  lvcreate logvol volgroup mbytes
@@ -583,6 +595,24 @@ the string C<,> (comma).
 B<This command is dangerous.  Without careful use you
 can easily destroy all your data>.
 
+=head2 stat
+
+ stat path
+
+Returns file information for the given C<path>.
+
+This is the same as the C<stat(2)> system call.
+
+=head2 statvfs
+
+ statvfs path
+
+Returns file system statistics for any mounted file system.
+C<path> should be a file or directory in the mounted file system
+(typically it is the mount point itself, but it doesn't need to be).
+
+This is the same as the C<statvfs(2)> system call.
+
 =head2 sync
 
  sync
index 5bd9628..03378e0 100644 (file)
@@ -58,7 +58,8 @@ On success this returns a pair containing the
 number of nodes in the nodeset, and a boolean flag
 if a node was created.
 
-This function returns a C<struct guestfs_int_bool *>.
+This function returns a C<struct guestfs_int_bool *>,
+or NULL if there was an error.
 I<The caller must call C<guestfs_free_int_bool> after use>.
 
 =head2 guestfs_aug_defvar
@@ -500,6 +501,24 @@ This function returns a NULL-terminated array of strings
 (like L<environ(3)>), or NULL if there was an error.
 I<The caller must free the strings and the array after use>.
 
+=head2 guestfs_lstat
+
+ struct guestfs_stat *guestfs_lstat (guestfs_h *handle,
+               const char *path);
+
+Returns file information for the given C<path>.
+
+This is the same as C<guestfs_stat> except that if C<path>
+is a symbolic link, then the link is stat-ed, not the file it
+refers to.
+
+This is the same as the C<lstat(2)> system call.
+
+This function returns a C<struct guestfs_stat *>
+(see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
+I<The caller must call C<free> after use>.
+
 =head2 guestfs_lvcreate
 
  int guestfs_lvcreate (guestfs_h *handle,
@@ -547,7 +566,9 @@ I<The caller must free the strings and the array after use>.
 List all the logical volumes detected.  This is the equivalent
 of the L<lvs(8)> command.  The "full" version includes all fields.
 
-This function returns a C<struct guestfs_lvm_lv_list *>.
+This function returns a C<struct guestfs_lvm_lv_list *>
+(see E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
 I<The caller must call C<guestfs_free_lvm_lv_list> after use>.
 
 =head2 guestfs_mkdir
@@ -653,7 +674,9 @@ I<The caller must free the strings and the array after use>.
 List all the physical volumes detected.  This is the equivalent
 of the L<pvs(8)> command.  The "full" version includes all fields.
 
-This function returns a C<struct guestfs_lvm_pv_list *>.
+This function returns a C<struct guestfs_lvm_pv_list *>
+(see E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
 I<The caller must call C<guestfs_free_lvm_pv_list> after use>.
 
 =head2 guestfs_read_lines
@@ -778,6 +801,36 @@ This function returns 0 on success or -1 on error.
 B<This command is dangerous.  Without careful use you
 can easily destroy all your data>.
 
+=head2 guestfs_stat
+
+ struct guestfs_stat *guestfs_stat (guestfs_h *handle,
+               const char *path);
+
+Returns file information for the given C<path>.
+
+This is the same as the C<stat(2)> system call.
+
+This function returns a C<struct guestfs_stat *>
+(see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
+I<The caller must call C<free> after use>.
+
+=head2 guestfs_statvfs
+
+ struct guestfs_statvfs *guestfs_statvfs (guestfs_h *handle,
+               const char *path);
+
+Returns file system statistics for any mounted file system.
+C<path> should be a file or directory in the mounted file system
+(typically it is the mount point itself, but it doesn't need to be).
+
+This is the same as the C<statvfs(2)> system call.
+
+This function returns a C<struct guestfs_statvfs *>
+(see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
+I<The caller must call C<free> after use>.
+
 =head2 guestfs_sync
 
  int guestfs_sync (guestfs_h *handle);
@@ -856,7 +909,9 @@ I<The caller must free the strings and the array after use>.
 List all the volumes groups detected.  This is the equivalent
 of the L<vgs(8)> command.  The "full" version includes all fields.
 
-This function returns a C<struct guestfs_lvm_vg_list *>.
+This function returns a C<struct guestfs_lvm_vg_list *>
+(see E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
 I<The caller must call C<guestfs_free_lvm_vg_list> after use>.
 
 =head2 guestfs_wait_ready
index fa2e341..f0344ac 100644 (file)
@@ -85,6 +85,36 @@ type lvm_lv = {
   modules : string;
 }
 
+type stat = {
+  dev : int64;
+  ino : int64;
+  mode : int64;
+  nlink : int64;
+  uid : int64;
+  gid : int64;
+  rdev : int64;
+  size : int64;
+  blksize : int64;
+  blocks : int64;
+  atime : int64;
+  mtime : int64;
+  ctime : int64;
+}
+
+type statvfs = {
+  bsize : int64;
+  frsize : int64;
+  blocks : int64;
+  bfree : int64;
+  bavail : int64;
+  files : int64;
+  ffree : int64;
+  favail : int64;
+  fsid : int64;
+  flag : int64;
+  namemax : int64;
+}
+
 external launch : t -> unit = "ocaml_guestfs_launch"
 external wait_ready : t -> unit = "ocaml_guestfs_wait_ready"
 external kill_subprocess : t -> unit = "ocaml_guestfs_kill_subprocess"
@@ -148,3 +178,6 @@ external lvm_remove_all : t -> unit = "ocaml_guestfs_lvm_remove_all"
 external file : t -> string -> string = "ocaml_guestfs_file"
 external command : t -> string array -> string = "ocaml_guestfs_command"
 external command_lines : t -> string array -> string array = "ocaml_guestfs_command_lines"
+external stat : t -> string -> stat = "ocaml_guestfs_stat"
+external lstat : t -> string -> stat = "ocaml_guestfs_lstat"
+external statvfs : t -> string -> statvfs = "ocaml_guestfs_statvfs"
index 279ed4d..3062968 100644 (file)
@@ -94,6 +94,36 @@ type lvm_lv = {
   modules : string;
 }
 
+type stat = {
+  dev : int64;
+  ino : int64;
+  mode : int64;
+  nlink : int64;
+  uid : int64;
+  gid : int64;
+  rdev : int64;
+  size : int64;
+  blksize : int64;
+  blocks : int64;
+  atime : int64;
+  mtime : int64;
+  ctime : int64;
+}
+
+type statvfs = {
+  bsize : int64;
+  frsize : int64;
+  blocks : int64;
+  bfree : int64;
+  bavail : int64;
+  files : int64;
+  ffree : int64;
+  favail : int64;
+  fsid : int64;
+  flag : int64;
+  namemax : int64;
+}
+
 val launch : t -> unit
 (** launch the qemu subprocess *)
 
@@ -283,3 +313,12 @@ val command : t -> string array -> string
 val command_lines : t -> string array -> string array
 (** run a command, returning lines *)
 
+val stat : t -> string -> stat
+(** get file information *)
+
+val lstat : t -> string -> stat
+(** get file information for a symbolic link *)
+
+val statvfs : t -> string -> statvfs
+(** get file system statistics *)
+
index 356965d..01fbcb0 100644 (file)
@@ -233,6 +233,74 @@ copy_lvm_lv_list (const struct guestfs_lvm_lv_list *lvs)
   }
 }
 
+static CAMLprim value
+copy_stat (const struct guestfs_stat *stat)
+{
+  CAMLparam0 ();
+  CAMLlocal2 (rv, v);
+
+  rv = caml_alloc (13, 0);
+  v = caml_copy_int64 (stat->dev);
+  Store_field (rv, 0, v);
+  v = caml_copy_int64 (stat->ino);
+  Store_field (rv, 1, v);
+  v = caml_copy_int64 (stat->mode);
+  Store_field (rv, 2, v);
+  v = caml_copy_int64 (stat->nlink);
+  Store_field (rv, 3, v);
+  v = caml_copy_int64 (stat->uid);
+  Store_field (rv, 4, v);
+  v = caml_copy_int64 (stat->gid);
+  Store_field (rv, 5, v);
+  v = caml_copy_int64 (stat->rdev);
+  Store_field (rv, 6, v);
+  v = caml_copy_int64 (stat->size);
+  Store_field (rv, 7, v);
+  v = caml_copy_int64 (stat->blksize);
+  Store_field (rv, 8, v);
+  v = caml_copy_int64 (stat->blocks);
+  Store_field (rv, 9, v);
+  v = caml_copy_int64 (stat->atime);
+  Store_field (rv, 10, v);
+  v = caml_copy_int64 (stat->mtime);
+  Store_field (rv, 11, v);
+  v = caml_copy_int64 (stat->ctime);
+  Store_field (rv, 12, v);
+  CAMLreturn (rv);
+}
+
+static CAMLprim value
+copy_statvfs (const struct guestfs_statvfs *statvfs)
+{
+  CAMLparam0 ();
+  CAMLlocal2 (rv, v);
+
+  rv = caml_alloc (11, 0);
+  v = caml_copy_int64 (statvfs->bsize);
+  Store_field (rv, 0, v);
+  v = caml_copy_int64 (statvfs->frsize);
+  Store_field (rv, 1, v);
+  v = caml_copy_int64 (statvfs->blocks);
+  Store_field (rv, 2, v);
+  v = caml_copy_int64 (statvfs->bfree);
+  Store_field (rv, 3, v);
+  v = caml_copy_int64 (statvfs->bavail);
+  Store_field (rv, 4, v);
+  v = caml_copy_int64 (statvfs->files);
+  Store_field (rv, 5, v);
+  v = caml_copy_int64 (statvfs->ffree);
+  Store_field (rv, 6, v);
+  v = caml_copy_int64 (statvfs->favail);
+  Store_field (rv, 7, v);
+  v = caml_copy_int64 (statvfs->fsid);
+  Store_field (rv, 8, v);
+  v = caml_copy_int64 (statvfs->flag);
+  Store_field (rv, 9, v);
+  v = caml_copy_int64 (statvfs->namemax);
+  Store_field (rv, 10, v);
+  CAMLreturn (rv);
+}
+
 CAMLprim value
 ocaml_guestfs_launch (value gv)
 {
@@ -1741,3 +1809,75 @@ ocaml_guestfs_command_lines (value gv, value argumentsv)
   CAMLreturn (rv);
 }
 
+CAMLprim value
+ocaml_guestfs_stat (value gv, value pathv)
+{
+  CAMLparam2 (gv, pathv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("stat: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  struct guestfs_stat *r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_stat (g, path);
+  caml_leave_blocking_section ();
+  if (r == NULL)
+    ocaml_guestfs_raise_error (g, "stat");
+
+  rv = copy_stat (r);
+  free (r);
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_lstat (value gv, value pathv)
+{
+  CAMLparam2 (gv, pathv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("lstat: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  struct guestfs_stat *r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_lstat (g, path);
+  caml_leave_blocking_section ();
+  if (r == NULL)
+    ocaml_guestfs_raise_error (g, "lstat");
+
+  rv = copy_stat (r);
+  free (r);
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_statvfs (value gv, value pathv)
+{
+  CAMLparam2 (gv, pathv);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("statvfs: used handle after closing it");
+
+  const char *path = String_val (pathv);
+  struct guestfs_statvfs *r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_statvfs (g, path);
+  caml_leave_blocking_section ();
+  if (r == NULL)
+    ocaml_guestfs_raise_error (g, "statvfs");
+
+  rv = copy_statvfs (r);
+  free (r);
+  CAMLreturn (rv);
+}
+
index c1eaa11..37a15e0 100644 (file)
@@ -1011,3 +1011,79 @@ PREINIT:
       }
       free (lines);
 
+void
+stat (g, path)
+      guestfs_h *g;
+      char *path;
+PREINIT:
+      struct guestfs_stat *statbuf;
+ PPCODE:
+      statbuf = guestfs_stat (g, path);
+      if (statbuf == NULL)
+        croak ("stat: %s", guestfs_last_error (g));
+      EXTEND (SP, 13);
+      PUSHs (sv_2mortal (my_newSVll (statbuf->dev)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->ino)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->mode)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->nlink)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->uid)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->gid)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->rdev)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->size)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->blksize)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->blocks)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->atime)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->mtime)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->ctime)));
+      free (statbuf);
+
+void
+lstat (g, path)
+      guestfs_h *g;
+      char *path;
+PREINIT:
+      struct guestfs_stat *statbuf;
+ PPCODE:
+      statbuf = guestfs_lstat (g, path);
+      if (statbuf == NULL)
+        croak ("lstat: %s", guestfs_last_error (g));
+      EXTEND (SP, 13);
+      PUSHs (sv_2mortal (my_newSVll (statbuf->dev)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->ino)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->mode)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->nlink)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->uid)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->gid)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->rdev)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->size)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->blksize)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->blocks)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->atime)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->mtime)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->ctime)));
+      free (statbuf);
+
+void
+statvfs (g, path)
+      guestfs_h *g;
+      char *path;
+PREINIT:
+      struct guestfs_statvfs *statbuf;
+ PPCODE:
+      statbuf = guestfs_statvfs (g, path);
+      if (statbuf == NULL)
+        croak ("statvfs: %s", guestfs_last_error (g));
+      EXTEND (SP, 11);
+      PUSHs (sv_2mortal (my_newSVll (statbuf->bsize)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->frsize)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->blocks)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->bfree)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->bavail)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->files)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->ffree)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->favail)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->fsid)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->flag)));
+      PUSHs (sv_2mortal (my_newSVll (statbuf->namemax)));
+      free (statbuf);
+
index c9caf08..09663bc 100644 (file)
@@ -402,6 +402,16 @@ hidden files are shown.
 This command is mostly useful for interactive sessions.  Programs
 should probably use C<$h-E<gt>readdir> instead.
 
+=item %statbuf = $h->lstat ($path);
+
+Returns file information for the given C<path>.
+
+This is the same as C<$h-E<gt>stat> except that if C<path>
+is a symbolic link, then the link is stat-ed, not the file it
+refers to.
+
+This is the same as the C<lstat(2)> system call.
+
 =item $h->lvcreate ($logvol, $volgroup, $mbytes);
 
 This creates an LVM volume group called C<logvol>
@@ -568,6 +578,20 @@ the string C<,> (comma).
 B<This command is dangerous.  Without careful use you
 can easily destroy all your data>.
 
+=item %statbuf = $h->stat ($path);
+
+Returns file information for the given C<path>.
+
+This is the same as the C<stat(2)> system call.
+
+=item %statbuf = $h->statvfs ($path);
+
+Returns file system statistics for any mounted file system.
+C<path> should be a file or directory in the mounted file system
+(typically it is the mount point itself, but it doesn't need to be).
+
+This is the same as the C<statvfs(2)> system call.
+
 =item $h->sync ();
 
 This syncs the disk, so that any writes are flushed through to the
index 8c7ad22..81c8798 100644 (file)
@@ -303,6 +303,72 @@ put_lvm_lv_list (struct guestfs_lvm_lv_list *lvs)
 };
 
 static PyObject *
+put_stat (struct guestfs_stat *stat)
+{
+  PyObject *dict;
+
+  dict = PyDict_New ();
+  PyDict_SetItemString (dict, "dev",
+                        PyLong_FromLongLong (stat->dev));
+  PyDict_SetItemString (dict, "ino",
+                        PyLong_FromLongLong (stat->ino));
+  PyDict_SetItemString (dict, "mode",
+                        PyLong_FromLongLong (stat->mode));
+  PyDict_SetItemString (dict, "nlink",
+                        PyLong_FromLongLong (stat->nlink));
+  PyDict_SetItemString (dict, "uid",
+                        PyLong_FromLongLong (stat->uid));
+  PyDict_SetItemString (dict, "gid",
+                        PyLong_FromLongLong (stat->gid));
+  PyDict_SetItemString (dict, "rdev",
+                        PyLong_FromLongLong (stat->rdev));
+  PyDict_SetItemString (dict, "size",
+                        PyLong_FromLongLong (stat->size));
+  PyDict_SetItemString (dict, "blksize",
+                        PyLong_FromLongLong (stat->blksize));
+  PyDict_SetItemString (dict, "blocks",
+                        PyLong_FromLongLong (stat->blocks));
+  PyDict_SetItemString (dict, "atime",
+                        PyLong_FromLongLong (stat->atime));
+  PyDict_SetItemString (dict, "mtime",
+                        PyLong_FromLongLong (stat->mtime));
+  PyDict_SetItemString (dict, "ctime",
+                        PyLong_FromLongLong (stat->ctime));
+  return dict;
+};
+
+static PyObject *
+put_statvfs (struct guestfs_statvfs *statvfs)
+{
+  PyObject *dict;
+
+  dict = PyDict_New ();
+  PyDict_SetItemString (dict, "bsize",
+                        PyLong_FromLongLong (statvfs->bsize));
+  PyDict_SetItemString (dict, "frsize",
+                        PyLong_FromLongLong (statvfs->frsize));
+  PyDict_SetItemString (dict, "blocks",
+                        PyLong_FromLongLong (statvfs->blocks));
+  PyDict_SetItemString (dict, "bfree",
+                        PyLong_FromLongLong (statvfs->bfree));
+  PyDict_SetItemString (dict, "bavail",
+                        PyLong_FromLongLong (statvfs->bavail));
+  PyDict_SetItemString (dict, "files",
+                        PyLong_FromLongLong (statvfs->files));
+  PyDict_SetItemString (dict, "ffree",
+                        PyLong_FromLongLong (statvfs->ffree));
+  PyDict_SetItemString (dict, "favail",
+                        PyLong_FromLongLong (statvfs->favail));
+  PyDict_SetItemString (dict, "fsid",
+                        PyLong_FromLongLong (statvfs->fsid));
+  PyDict_SetItemString (dict, "flag",
+                        PyLong_FromLongLong (statvfs->flag));
+  PyDict_SetItemString (dict, "namemax",
+                        PyLong_FromLongLong (statvfs->namemax));
+  return dict;
+};
+
+static PyObject *
 py_guestfs_launch (PyObject *self, PyObject *args)
 {
   PyObject *py_g;
@@ -1889,6 +1955,81 @@ py_guestfs_command_lines (PyObject *self, PyObject *args)
   return py_r;
 }
 
+static PyObject *
+py_guestfs_stat (PyObject *self, PyObject *args)
+{
+  PyObject *py_g;
+  guestfs_h *g;
+  PyObject *py_r;
+  struct guestfs_stat *r;
+  const char *path;
+
+  if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_stat",
+                         &py_g, &path))
+    return NULL;
+  g = get_handle (py_g);
+
+  r = guestfs_stat (g, path);
+  if (r == NULL) {
+    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+    return NULL;
+  }
+
+  py_r = put_stat (r);
+  free (r);
+  return py_r;
+}
+
+static PyObject *
+py_guestfs_lstat (PyObject *self, PyObject *args)
+{
+  PyObject *py_g;
+  guestfs_h *g;
+  PyObject *py_r;
+  struct guestfs_stat *r;
+  const char *path;
+
+  if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_lstat",
+                         &py_g, &path))
+    return NULL;
+  g = get_handle (py_g);
+
+  r = guestfs_lstat (g, path);
+  if (r == NULL) {
+    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+    return NULL;
+  }
+
+  py_r = put_stat (r);
+  free (r);
+  return py_r;
+}
+
+static PyObject *
+py_guestfs_statvfs (PyObject *self, PyObject *args)
+{
+  PyObject *py_g;
+  guestfs_h *g;
+  PyObject *py_r;
+  struct guestfs_statvfs *r;
+  const char *path;
+
+  if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_statvfs",
+                         &py_g, &path))
+    return NULL;
+  g = get_handle (py_g);
+
+  r = guestfs_statvfs (g, path);
+  if (r == NULL) {
+    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+    return NULL;
+  }
+
+  py_r = put_statvfs (r);
+  free (r);
+  return py_r;
+}
+
 static PyMethodDef methods[] = {
   { (char *) "create", py_guestfs_create, METH_VARARGS, NULL },
   { (char *) "close", py_guestfs_close, METH_VARARGS, NULL },
@@ -1955,6 +2096,9 @@ static PyMethodDef methods[] = {
   { (char *) "file", py_guestfs_file, METH_VARARGS, NULL },
   { (char *) "command", py_guestfs_command, METH_VARARGS, NULL },
   { (char *) "command_lines", py_guestfs_command_lines, METH_VARARGS, NULL },
+  { (char *) "stat", py_guestfs_stat, METH_VARARGS, NULL },
+  { (char *) "lstat", py_guestfs_lstat, METH_VARARGS, NULL },
+  { (char *) "statvfs", py_guestfs_statvfs, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
 };
 
index 6cf7e19..2e0be5c 100644 (file)
@@ -216,3 +216,12 @@ class GuestFS:
     def command_lines (self, arguments):
         return libguestfsmod.command_lines (self._o, arguments)
 
+    def stat (self, path):
+        return libguestfsmod.stat (self._o, path)
+
+    def lstat (self, path):
+        return libguestfsmod.lstat (self._o, path)
+
+    def statvfs (self, path):
+        return libguestfsmod.statvfs (self._o, path)
+
index c6f574a..8f40102 100644 (file)
@@ -3699,3 +3699,228 @@ char **guestfs_command_lines (guestfs_h *g,
   return rv.ret.lines.lines_val;
 }
 
+struct stat_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_stat_ret ret;
+};
+
+static void stat_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct stat_rv *rv = (struct stat_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_stat: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_stat: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_stat_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_stat: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+struct guestfs_stat *guestfs_stat (guestfs_h *g,
+               const char *path)
+{
+  struct guestfs_stat_args args;
+  struct stat_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_stat called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  serial = dispatch (g, GUESTFS_PROC_STAT,
+                     (xdrproc_t) xdr_guestfs_stat_args, (char *) &args);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = stat_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_stat failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_STAT, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller will free this */
+  return safe_memdup (g, &rv.ret.statbuf, sizeof (rv.ret.statbuf));
+}
+
+struct lstat_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_lstat_ret ret;
+};
+
+static void lstat_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct lstat_rv *rv = (struct lstat_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_lstat: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_lstat: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_lstat_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_lstat: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+struct guestfs_stat *guestfs_lstat (guestfs_h *g,
+               const char *path)
+{
+  struct guestfs_lstat_args args;
+  struct lstat_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_lstat called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  serial = dispatch (g, GUESTFS_PROC_LSTAT,
+                     (xdrproc_t) xdr_guestfs_lstat_args, (char *) &args);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = lstat_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_lstat failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LSTAT, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller will free this */
+  return safe_memdup (g, &rv.ret.statbuf, sizeof (rv.ret.statbuf));
+}
+
+struct statvfs_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_statvfs_ret ret;
+};
+
+static void statvfs_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct statvfs_rv *rv = (struct statvfs_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_statvfs: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_statvfs: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_statvfs_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_statvfs: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g,
+               const char *path)
+{
+  struct guestfs_statvfs_args args;
+  struct statvfs_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_statvfs called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  args.path = (char *) path;
+  serial = dispatch (g, GUESTFS_PROC_STATVFS,
+                     (xdrproc_t) xdr_guestfs_statvfs_args, (char *) &args);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = statvfs_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_statvfs failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_STATVFS, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller will free this */
+  return safe_memdup (g, &rv.ret.statbuf, sizeof (rv.ret.statbuf));
+}
+
index 06efabf..a838a04 100644 (file)
@@ -82,3 +82,6 @@ extern int guestfs_lvm_remove_all (guestfs_h *handle);
 extern char *guestfs_file (guestfs_h *handle, const char *path);
 extern char *guestfs_command (guestfs_h *handle, char * const* const arguments);
 extern char **guestfs_command_lines (guestfs_h *handle, char * const* const arguments);
+extern struct guestfs_stat *guestfs_stat (guestfs_h *handle, const char *path);
+extern struct guestfs_stat *guestfs_lstat (guestfs_h *handle, const char *path);
+extern struct guestfs_statvfs *guestfs_statvfs (guestfs_h *handle, const char *path);
index b3751cd..76ac819 100644 (file)
@@ -97,3 +97,33 @@ struct guestfs_lvm_lv_list {
   struct guestfs_lvm_lv *val;
 };
 
+struct guestfs_stat {
+  int64_t dev;
+  int64_t ino;
+  int64_t mode;
+  int64_t nlink;
+  int64_t uid;
+  int64_t gid;
+  int64_t rdev;
+  int64_t size;
+  int64_t blksize;
+  int64_t blocks;
+  int64_t atime;
+  int64_t mtime;
+  int64_t ctime;
+};
+
+struct guestfs_statvfs {
+  int64_t bsize;
+  int64_t frsize;
+  int64_t blocks;
+  int64_t bfree;
+  int64_t bavail;
+  int64_t files;
+  int64_t ffree;
+  int64_t favail;
+  int64_t fsid;
+  int64_t flag;
+  int64_t namemax;
+};
+
index 0849f7a..99377b4 100644 (file)
@@ -174,6 +174,70 @@ xdr_guestfs_lvm_int_lv_list (XDR *xdrs, guestfs_lvm_int_lv_list *objp)
 }
 
 bool_t
+xdr_guestfs_int_stat (XDR *xdrs, guestfs_int_stat *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_quad_t (xdrs, &objp->dev))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->ino))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->mode))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->nlink))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->uid))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->gid))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->rdev))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->size))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->blksize))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->blocks))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->atime))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->mtime))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->ctime))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_int_statvfs (XDR *xdrs, guestfs_int_statvfs *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_quad_t (xdrs, &objp->bsize))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->frsize))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->blocks))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->bfree))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->bavail))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->files))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->ffree))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->favail))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->fsid))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->flag))
+                return FALSE;
+        if (!xdr_quad_t (xdrs, &objp->namemax))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
 xdr_guestfs_mount_args (XDR *xdrs, guestfs_mount_args *objp)
 {
        register int32_t *buf;
@@ -890,6 +954,66 @@ xdr_guestfs_command_lines_ret (XDR *xdrs, guestfs_command_lines_ret *objp)
 }
 
 bool_t
+xdr_guestfs_stat_args (XDR *xdrs, guestfs_stat_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_stat_ret (XDR *xdrs, guestfs_stat_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_guestfs_int_stat (xdrs, &objp->statbuf))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_lstat_args (XDR *xdrs, guestfs_lstat_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_lstat_ret (XDR *xdrs, guestfs_lstat_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_guestfs_int_stat (xdrs, &objp->statbuf))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_statvfs_args (XDR *xdrs, guestfs_statvfs_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_statvfs_ret (XDR *xdrs, guestfs_statvfs_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_guestfs_int_statvfs (xdrs, &objp->statbuf))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
 xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
 {
        register int32_t *buf;
index 4b31468..0720723 100644 (file)
@@ -92,6 +92,38 @@ typedef struct {
        guestfs_lvm_int_lv *guestfs_lvm_int_lv_list_val;
 } guestfs_lvm_int_lv_list;
 
+struct guestfs_int_stat {
+       quad_t dev;
+       quad_t ino;
+       quad_t mode;
+       quad_t nlink;
+       quad_t uid;
+       quad_t gid;
+       quad_t rdev;
+       quad_t size;
+       quad_t blksize;
+       quad_t blocks;
+       quad_t atime;
+       quad_t mtime;
+       quad_t ctime;
+};
+typedef struct guestfs_int_stat guestfs_int_stat;
+
+struct guestfs_int_statvfs {
+       quad_t bsize;
+       quad_t frsize;
+       quad_t blocks;
+       quad_t bfree;
+       quad_t bavail;
+       quad_t files;
+       quad_t ffree;
+       quad_t favail;
+       quad_t fsid;
+       quad_t flag;
+       quad_t namemax;
+};
+typedef struct guestfs_int_statvfs guestfs_int_statvfs;
+
 struct guestfs_mount_args {
        char *device;
        char *mountpoint;
@@ -465,6 +497,36 @@ struct guestfs_command_lines_ret {
 };
 typedef struct guestfs_command_lines_ret guestfs_command_lines_ret;
 
+struct guestfs_stat_args {
+       char *path;
+};
+typedef struct guestfs_stat_args guestfs_stat_args;
+
+struct guestfs_stat_ret {
+       guestfs_int_stat statbuf;
+};
+typedef struct guestfs_stat_ret guestfs_stat_ret;
+
+struct guestfs_lstat_args {
+       char *path;
+};
+typedef struct guestfs_lstat_args guestfs_lstat_args;
+
+struct guestfs_lstat_ret {
+       guestfs_int_stat statbuf;
+};
+typedef struct guestfs_lstat_ret guestfs_lstat_ret;
+
+struct guestfs_statvfs_args {
+       char *path;
+};
+typedef struct guestfs_statvfs_args guestfs_statvfs_args;
+
+struct guestfs_statvfs_ret {
+       guestfs_int_statvfs statbuf;
+};
+typedef struct guestfs_statvfs_ret guestfs_statvfs_ret;
+
 enum guestfs_procedure {
        GUESTFS_PROC_MOUNT = 1,
        GUESTFS_PROC_SYNC = 2,
@@ -517,7 +579,10 @@ enum guestfs_procedure {
        GUESTFS_PROC_FILE = 49,
        GUESTFS_PROC_COMMAND = 50,
        GUESTFS_PROC_COMMAND_LINES = 51,
-       GUESTFS_PROC_dummy = 51 + 1,
+       GUESTFS_PROC_STAT = 52,
+       GUESTFS_PROC_LSTAT = 53,
+       GUESTFS_PROC_STATVFS = 54,
+       GUESTFS_PROC_dummy = 54 + 1,
 };
 typedef enum guestfs_procedure guestfs_procedure;
 #define GUESTFS_MESSAGE_MAX 4194304
@@ -562,6 +627,8 @@ extern  bool_t xdr_guestfs_lvm_int_vg (XDR *, guestfs_lvm_int_vg*);
 extern  bool_t xdr_guestfs_lvm_int_vg_list (XDR *, guestfs_lvm_int_vg_list*);
 extern  bool_t xdr_guestfs_lvm_int_lv (XDR *, guestfs_lvm_int_lv*);
 extern  bool_t xdr_guestfs_lvm_int_lv_list (XDR *, guestfs_lvm_int_lv_list*);
+extern  bool_t xdr_guestfs_int_stat (XDR *, guestfs_int_stat*);
+extern  bool_t xdr_guestfs_int_statvfs (XDR *, guestfs_int_statvfs*);
 extern  bool_t xdr_guestfs_mount_args (XDR *, guestfs_mount_args*);
 extern  bool_t xdr_guestfs_touch_args (XDR *, guestfs_touch_args*);
 extern  bool_t xdr_guestfs_cat_args (XDR *, guestfs_cat_args*);
@@ -623,6 +690,12 @@ extern  bool_t xdr_guestfs_command_args (XDR *, guestfs_command_args*);
 extern  bool_t xdr_guestfs_command_ret (XDR *, guestfs_command_ret*);
 extern  bool_t xdr_guestfs_command_lines_args (XDR *, guestfs_command_lines_args*);
 extern  bool_t xdr_guestfs_command_lines_ret (XDR *, guestfs_command_lines_ret*);
+extern  bool_t xdr_guestfs_stat_args (XDR *, guestfs_stat_args*);
+extern  bool_t xdr_guestfs_stat_ret (XDR *, guestfs_stat_ret*);
+extern  bool_t xdr_guestfs_lstat_args (XDR *, guestfs_lstat_args*);
+extern  bool_t xdr_guestfs_lstat_ret (XDR *, guestfs_lstat_ret*);
+extern  bool_t xdr_guestfs_statvfs_args (XDR *, guestfs_statvfs_args*);
+extern  bool_t xdr_guestfs_statvfs_ret (XDR *, guestfs_statvfs_ret*);
 extern  bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*);
 extern  bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
 extern  bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
@@ -637,6 +710,8 @@ extern bool_t xdr_guestfs_lvm_int_vg ();
 extern bool_t xdr_guestfs_lvm_int_vg_list ();
 extern bool_t xdr_guestfs_lvm_int_lv ();
 extern bool_t xdr_guestfs_lvm_int_lv_list ();
+extern bool_t xdr_guestfs_int_stat ();
+extern bool_t xdr_guestfs_int_statvfs ();
 extern bool_t xdr_guestfs_mount_args ();
 extern bool_t xdr_guestfs_touch_args ();
 extern bool_t xdr_guestfs_cat_args ();
@@ -698,6 +773,12 @@ extern bool_t xdr_guestfs_command_args ();
 extern bool_t xdr_guestfs_command_ret ();
 extern bool_t xdr_guestfs_command_lines_args ();
 extern bool_t xdr_guestfs_command_lines_ret ();
+extern bool_t xdr_guestfs_stat_args ();
+extern bool_t xdr_guestfs_stat_ret ();
+extern bool_t xdr_guestfs_lstat_args ();
+extern bool_t xdr_guestfs_lstat_ret ();
+extern bool_t xdr_guestfs_statvfs_args ();
+extern bool_t xdr_guestfs_statvfs_ret ();
 extern bool_t xdr_guestfs_procedure ();
 extern bool_t xdr_guestfs_message_direction ();
 extern bool_t xdr_guestfs_message_status ();
index 68362d6..e03aef6 100644 (file)
@@ -85,6 +85,36 @@ struct guestfs_lvm_int_lv {
 
 typedef struct guestfs_lvm_int_lv guestfs_lvm_int_lv_list<>;
 
+struct guestfs_int_stat {
+  hyper dev;
+  hyper ino;
+  hyper mode;
+  hyper nlink;
+  hyper uid;
+  hyper gid;
+  hyper rdev;
+  hyper size;
+  hyper blksize;
+  hyper blocks;
+  hyper atime;
+  hyper mtime;
+  hyper ctime;
+};
+
+struct guestfs_int_statvfs {
+  hyper bsize;
+  hyper frsize;
+  hyper blocks;
+  hyper bfree;
+  hyper bavail;
+  hyper files;
+  hyper ffree;
+  hyper favail;
+  hyper fsid;
+  hyper flag;
+  hyper namemax;
+};
+
 struct guestfs_mount_args {
   string device<>;
   string mountpoint<>;
@@ -352,6 +382,30 @@ struct guestfs_command_lines_ret {
   str lines<>;
 };
 
+struct guestfs_stat_args {
+  string path<>;
+};
+
+struct guestfs_stat_ret {
+  guestfs_int_stat statbuf;
+};
+
+struct guestfs_lstat_args {
+  string path<>;
+};
+
+struct guestfs_lstat_ret {
+  guestfs_int_stat statbuf;
+};
+
+struct guestfs_statvfs_args {
+  string path<>;
+};
+
+struct guestfs_statvfs_ret {
+  guestfs_int_statvfs statbuf;
+};
+
 enum guestfs_procedure {
   GUESTFS_PROC_MOUNT = 1,
   GUESTFS_PROC_SYNC = 2,
@@ -404,6 +458,9 @@ enum guestfs_procedure {
   GUESTFS_PROC_FILE = 49,
   GUESTFS_PROC_COMMAND = 50,
   GUESTFS_PROC_COMMAND_LINES = 51,
+  GUESTFS_PROC_STAT = 52,
+  GUESTFS_PROC_LSTAT = 53,
+  GUESTFS_PROC_STATVFS = 54,
   GUESTFS_PROC_dummy
 };
 
diff --git a/tests.c b/tests.c
index b59192c..1c6676b 100644 (file)
--- a/tests.c
+++ b/tests.c
@@ -1238,288 +1238,6 @@ static int test_lvs_1 (void)
   return 0;
 }
 
-static int test_pvs_full_0 (void)
-{
-  /* InitBasicFSonLVM for pvs_full (0): create ext2 on /dev/VG/LV */
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_umount_all (g);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_lvm_remove_all (g);
-    if (r == -1)
-      return -1;
-  }
-  {
-    char *lines[] = {
-      ",",
-      NULL
-    };
-    int r;
-    suppress_error = 0;
-    r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_pvcreate (g, "/dev/sda1");
-    if (r == -1)
-      return -1;
-  }
-  {
-    char *physvols[] = {
-      "/dev/sda1",
-      NULL
-    };
-    int r;
-    suppress_error = 0;
-    r = guestfs_vgcreate (g, "VG", physvols);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_lvcreate (g, "LV", "VG", 8);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_mkfs (g, "ext2", "/dev/VG/LV");
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_mount (g, "/dev/VG/LV", "/");
-    if (r == -1)
-      return -1;
-  }
-  /* TestOutputLength for pvs_full (0) */
-  {
-    char **r;
-    int i;
-    suppress_error = 0;
-    r = guestfs_pvs (g);
-    if (r == NULL)
-      return -1;
-    int j;
-    for (j = 0; j < 1; ++j)
-      if (r[j] == NULL) {
-        fprintf (stderr, "test_pvs_full_0: short list returned\n");
-        print_strings (r);
-        return -1;
-      }
-    if (r[j] != NULL) {
-      fprintf (stderr, "test_pvs_full_0: long list returned\n");
-      print_strings (r);
-      return -1;
-    }
-    for (i = 0; r[i] != NULL; ++i)
-      free (r[i]);
-    free (r);
-  }
-  return 0;
-}
-
-static int test_vgs_full_0 (void)
-{
-  /* InitBasicFSonLVM for vgs_full (0): create ext2 on /dev/VG/LV */
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_umount_all (g);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_lvm_remove_all (g);
-    if (r == -1)
-      return -1;
-  }
-  {
-    char *lines[] = {
-      ",",
-      NULL
-    };
-    int r;
-    suppress_error = 0;
-    r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_pvcreate (g, "/dev/sda1");
-    if (r == -1)
-      return -1;
-  }
-  {
-    char *physvols[] = {
-      "/dev/sda1",
-      NULL
-    };
-    int r;
-    suppress_error = 0;
-    r = guestfs_vgcreate (g, "VG", physvols);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_lvcreate (g, "LV", "VG", 8);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_mkfs (g, "ext2", "/dev/VG/LV");
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_mount (g, "/dev/VG/LV", "/");
-    if (r == -1)
-      return -1;
-  }
-  /* TestOutputLength for vgs_full (0) */
-  {
-    char **r;
-    int i;
-    suppress_error = 0;
-    r = guestfs_pvs (g);
-    if (r == NULL)
-      return -1;
-    int j;
-    for (j = 0; j < 1; ++j)
-      if (r[j] == NULL) {
-        fprintf (stderr, "test_vgs_full_0: short list returned\n");
-        print_strings (r);
-        return -1;
-      }
-    if (r[j] != NULL) {
-      fprintf (stderr, "test_vgs_full_0: long list returned\n");
-      print_strings (r);
-      return -1;
-    }
-    for (i = 0; r[i] != NULL; ++i)
-      free (r[i]);
-    free (r);
-  }
-  return 0;
-}
-
-static int test_lvs_full_0 (void)
-{
-  /* InitBasicFSonLVM for lvs_full (0): create ext2 on /dev/VG/LV */
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_umount_all (g);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_lvm_remove_all (g);
-    if (r == -1)
-      return -1;
-  }
-  {
-    char *lines[] = {
-      ",",
-      NULL
-    };
-    int r;
-    suppress_error = 0;
-    r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_pvcreate (g, "/dev/sda1");
-    if (r == -1)
-      return -1;
-  }
-  {
-    char *physvols[] = {
-      "/dev/sda1",
-      NULL
-    };
-    int r;
-    suppress_error = 0;
-    r = guestfs_vgcreate (g, "VG", physvols);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_lvcreate (g, "LV", "VG", 8);
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_mkfs (g, "ext2", "/dev/VG/LV");
-    if (r == -1)
-      return -1;
-  }
-  {
-    int r;
-    suppress_error = 0;
-    r = guestfs_mount (g, "/dev/VG/LV", "/");
-    if (r == -1)
-      return -1;
-  }
-  /* TestOutputLength for lvs_full (0) */
-  {
-    char **r;
-    int i;
-    suppress_error = 0;
-    r = guestfs_pvs (g);
-    if (r == NULL)
-      return -1;
-    int j;
-    for (j = 0; j < 1; ++j)
-      if (r[j] == NULL) {
-        fprintf (stderr, "test_lvs_full_0: short list returned\n");
-        print_strings (r);
-        return -1;
-      }
-    if (r[j] != NULL) {
-      fprintf (stderr, "test_lvs_full_0: long list returned\n");
-      print_strings (r);
-      return -1;
-    }
-    for (i = 0; r[i] != NULL; ++i)
-      free (r[i]);
-    free (r);
-  }
-  return 0;
-}
-
 static int test_read_lines_0 (void)
 {
   /* InitBasicFS for read_lines (0): create ext2 on /dev/sda1 */
@@ -3787,6 +3505,207 @@ static int test_file_2 (void)
   return 0;
 }
 
+static int test_stat_0 (void)
+{
+  /* InitBasicFS for stat (0): create ext2 on /dev/sda1 */
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_umount_all (g);
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_lvm_remove_all (g);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char *lines[] = {
+      ",",
+      NULL
+    };
+    int r;
+    suppress_error = 0;
+    r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_mount (g, "/dev/sda1", "/");
+    if (r == -1)
+      return -1;
+  }
+  /* TestOutputStruct for stat (0) */
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_touch (g, "/new");
+    if (r == -1)
+      return -1;
+  }
+  {
+    struct guestfs_stat *r;
+    suppress_error = 0;
+    r = guestfs_stat (g, "/new");
+    if (r == NULL)
+      return -1;
+    if (r->size != 0) {
+      fprintf (stderr, "test_stat_0: size was %d, expected 0\n",
+               (int) r->size);
+      return -1;
+    }
+    free (r);
+  }
+  return 0;
+}
+
+static int test_lstat_0 (void)
+{
+  /* InitBasicFS for lstat (0): create ext2 on /dev/sda1 */
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_umount_all (g);
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_lvm_remove_all (g);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char *lines[] = {
+      ",",
+      NULL
+    };
+    int r;
+    suppress_error = 0;
+    r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_mount (g, "/dev/sda1", "/");
+    if (r == -1)
+      return -1;
+  }
+  /* TestOutputStruct for lstat (0) */
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_touch (g, "/new");
+    if (r == -1)
+      return -1;
+  }
+  {
+    struct guestfs_stat *r;
+    suppress_error = 0;
+    r = guestfs_lstat (g, "/new");
+    if (r == NULL)
+      return -1;
+    if (r->size != 0) {
+      fprintf (stderr, "test_lstat_0: size was %d, expected 0\n",
+               (int) r->size);
+      return -1;
+    }
+    free (r);
+  }
+  return 0;
+}
+
+static int test_statvfs_0 (void)
+{
+  /* InitBasicFS for statvfs (0): create ext2 on /dev/sda1 */
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_umount_all (g);
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_lvm_remove_all (g);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char *lines[] = {
+      ",",
+      NULL
+    };
+    int r;
+    suppress_error = 0;
+    r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines);
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_mkfs (g, "ext2", "/dev/sda1");
+    if (r == -1)
+      return -1;
+  }
+  {
+    int r;
+    suppress_error = 0;
+    r = guestfs_mount (g, "/dev/sda1", "/");
+    if (r == -1)
+      return -1;
+  }
+  /* TestOutputStruct for statvfs (0) */
+  {
+    struct guestfs_statvfs *r;
+    suppress_error = 0;
+    r = guestfs_statvfs (g, "/");
+    if (r == NULL)
+      return -1;
+    if (r->bfree != 487702) {
+      fprintf (stderr, "test_statvfs_0: bfree was %d, expected 487702\n",
+               (int) r->bfree);
+      return -1;
+    }
+    if (r->blocks != 490020) {
+      fprintf (stderr, "test_statvfs_0: blocks was %d, expected 490020\n",
+               (int) r->blocks);
+      return -1;
+    }
+    if (r->bsize != 1024) {
+      fprintf (stderr, "test_statvfs_0: bsize was %d, expected 1024\n",
+               (int) r->bsize);
+      return -1;
+    }
+    free (r);
+  }
+  return 0;
+}
+
 int main (int argc, char *argv[])
 {
   char c = 0;
@@ -3794,6 +3713,7 @@ int main (int argc, char *argv[])
   const char *srcdir;
   int fd;
   char buf[256];
+  int nr_tests;
 
   g = guestfs_create ();
   if (g == NULL) {
@@ -3900,251 +3820,252 @@ int main (int argc, char *argv[])
     exit (1);
   }
 
-  printf ("  1/ 49 test_mount_0\n");
+  nr_tests = 49;
+  printf ("  1/%3d test_mount_0\n", nr_tests);
   if (test_mount_0 () == -1) {
     printf ("test_mount_0 FAILED\n");
     failed++;
   }
-  printf ("  2/ 49 test_sync_0\n");
+  printf ("  2/%3d test_sync_0\n", nr_tests);
   if (test_sync_0 () == -1) {
     printf ("test_sync_0 FAILED\n");
     failed++;
   }
-  printf ("  3/ 49 test_touch_0\n");
+  printf ("  3/%3d test_touch_0\n", nr_tests);
   if (test_touch_0 () == -1) {
     printf ("test_touch_0 FAILED\n");
     failed++;
   }
-  printf ("  4/ 49 test_cat_0\n");
+  printf ("  4/%3d test_cat_0\n", nr_tests);
   if (test_cat_0 () == -1) {
     printf ("test_cat_0 FAILED\n");
     failed++;
   }
-  printf ("  5/ 49 test_ls_0\n");
+  printf ("  5/%3d test_ls_0\n", nr_tests);
   if (test_ls_0 () == -1) {
     printf ("test_ls_0 FAILED\n");
     failed++;
   }
-  printf ("  6/ 49 test_list_devices_0\n");
+  printf ("  6/%3d test_list_devices_0\n", nr_tests);
   if (test_list_devices_0 () == -1) {
     printf ("test_list_devices_0 FAILED\n");
     failed++;
   }
-  printf ("  7/ 49 test_list_partitions_0\n");
+  printf ("  7/%3d test_list_partitions_0\n", nr_tests);
   if (test_list_partitions_0 () == -1) {
     printf ("test_list_partitions_0 FAILED\n");
     failed++;
   }
-  printf ("  8/ 49 test_list_partitions_1\n");
+  printf ("  8/%3d test_list_partitions_1\n", nr_tests);
   if (test_list_partitions_1 () == -1) {
     printf ("test_list_partitions_1 FAILED\n");
     failed++;
   }
-  printf ("  9/ 49 test_pvs_0\n");
+  printf ("  9/%3d test_pvs_0\n", nr_tests);
   if (test_pvs_0 () == -1) {
     printf ("test_pvs_0 FAILED\n");
     failed++;
   }
-  printf (" 10/ 49 test_pvs_1\n");
+  printf (" 10/%3d test_pvs_1\n", nr_tests);
   if (test_pvs_1 () == -1) {
     printf ("test_pvs_1 FAILED\n");
     failed++;
   }
-  printf (" 11/ 49 test_vgs_0\n");
+  printf (" 11/%3d test_vgs_0\n", nr_tests);
   if (test_vgs_0 () == -1) {
     printf ("test_vgs_0 FAILED\n");
     failed++;
   }
-  printf (" 12/ 49 test_vgs_1\n");
+  printf (" 12/%3d test_vgs_1\n", nr_tests);
   if (test_vgs_1 () == -1) {
     printf ("test_vgs_1 FAILED\n");
     failed++;
   }
-  printf (" 13/ 49 test_lvs_0\n");
+  printf (" 13/%3d test_lvs_0\n", nr_tests);
   if (test_lvs_0 () == -1) {
     printf ("test_lvs_0 FAILED\n");
     failed++;
   }
-  printf (" 14/ 49 test_lvs_1\n");
+  printf (" 14/%3d test_lvs_1\n", nr_tests);
   if (test_lvs_1 () == -1) {
     printf ("test_lvs_1 FAILED\n");
     failed++;
   }
-  printf (" 15/ 49 test_pvs_full_0\n");
-  if (test_pvs_full_0 () == -1) {
-    printf ("test_pvs_full_0 FAILED\n");
-    failed++;
-  }
-  printf (" 16/ 49 test_vgs_full_0\n");
-  if (test_vgs_full_0 () == -1) {
-    printf ("test_vgs_full_0 FAILED\n");
-    failed++;
-  }
-  printf (" 17/ 49 test_lvs_full_0\n");
-  if (test_lvs_full_0 () == -1) {
-    printf ("test_lvs_full_0 FAILED\n");
-    failed++;
-  }
-  printf (" 18/ 49 test_read_lines_0\n");
+  printf (" 15/%3d test_read_lines_0\n", nr_tests);
   if (test_read_lines_0 () == -1) {
     printf ("test_read_lines_0 FAILED\n");
     failed++;
   }
-  printf (" 19/ 49 test_read_lines_1\n");
+  printf (" 16/%3d test_read_lines_1\n", nr_tests);
   if (test_read_lines_1 () == -1) {
     printf ("test_read_lines_1 FAILED\n");
     failed++;
   }
-  printf (" 20/ 49 test_rm_0\n");
+  printf (" 17/%3d test_rm_0\n", nr_tests);
   if (test_rm_0 () == -1) {
     printf ("test_rm_0 FAILED\n");
     failed++;
   }
-  printf (" 21/ 49 test_rm_1\n");
+  printf (" 18/%3d test_rm_1\n", nr_tests);
   if (test_rm_1 () == -1) {
     printf ("test_rm_1 FAILED\n");
     failed++;
   }
-  printf (" 22/ 49 test_rm_2\n");
+  printf (" 19/%3d test_rm_2\n", nr_tests);
   if (test_rm_2 () == -1) {
     printf ("test_rm_2 FAILED\n");
     failed++;
   }
-  printf (" 23/ 49 test_rmdir_0\n");
+  printf (" 20/%3d test_rmdir_0\n", nr_tests);
   if (test_rmdir_0 () == -1) {
     printf ("test_rmdir_0 FAILED\n");
     failed++;
   }
-  printf (" 24/ 49 test_rmdir_1\n");
+  printf (" 21/%3d test_rmdir_1\n", nr_tests);
   if (test_rmdir_1 () == -1) {
     printf ("test_rmdir_1 FAILED\n");
     failed++;
   }
-  printf (" 25/ 49 test_rmdir_2\n");
+  printf (" 22/%3d test_rmdir_2\n", nr_tests);
   if (test_rmdir_2 () == -1) {
     printf ("test_rmdir_2 FAILED\n");
     failed++;
   }
-  printf (" 26/ 49 test_rm_rf_0\n");
+  printf (" 23/%3d test_rm_rf_0\n", nr_tests);
   if (test_rm_rf_0 () == -1) {
     printf ("test_rm_rf_0 FAILED\n");
     failed++;
   }
-  printf (" 27/ 49 test_mkdir_0\n");
+  printf (" 24/%3d test_mkdir_0\n", nr_tests);
   if (test_mkdir_0 () == -1) {
     printf ("test_mkdir_0 FAILED\n");
     failed++;
   }
-  printf (" 28/ 49 test_mkdir_1\n");
+  printf (" 25/%3d test_mkdir_1\n", nr_tests);
   if (test_mkdir_1 () == -1) {
     printf ("test_mkdir_1 FAILED\n");
     failed++;
   }
-  printf (" 29/ 49 test_mkdir_p_0\n");
+  printf (" 26/%3d test_mkdir_p_0\n", nr_tests);
   if (test_mkdir_p_0 () == -1) {
     printf ("test_mkdir_p_0 FAILED\n");
     failed++;
   }
-  printf (" 30/ 49 test_mkdir_p_1\n");
+  printf (" 27/%3d test_mkdir_p_1\n", nr_tests);
   if (test_mkdir_p_1 () == -1) {
     printf ("test_mkdir_p_1 FAILED\n");
     failed++;
   }
-  printf (" 31/ 49 test_mkdir_p_2\n");
+  printf (" 28/%3d test_mkdir_p_2\n", nr_tests);
   if (test_mkdir_p_2 () == -1) {
     printf ("test_mkdir_p_2 FAILED\n");
     failed++;
   }
-  printf (" 32/ 49 test_exists_0\n");
+  printf (" 29/%3d test_exists_0\n", nr_tests);
   if (test_exists_0 () == -1) {
     printf ("test_exists_0 FAILED\n");
     failed++;
   }
-  printf (" 33/ 49 test_exists_1\n");
+  printf (" 30/%3d test_exists_1\n", nr_tests);
   if (test_exists_1 () == -1) {
     printf ("test_exists_1 FAILED\n");
     failed++;
   }
-  printf (" 34/ 49 test_is_file_0\n");
+  printf (" 31/%3d test_is_file_0\n", nr_tests);
   if (test_is_file_0 () == -1) {
     printf ("test_is_file_0 FAILED\n");
     failed++;
   }
-  printf (" 35/ 49 test_is_file_1\n");
+  printf (" 32/%3d test_is_file_1\n", nr_tests);
   if (test_is_file_1 () == -1) {
     printf ("test_is_file_1 FAILED\n");
     failed++;
   }
-  printf (" 36/ 49 test_is_dir_0\n");
+  printf (" 33/%3d test_is_dir_0\n", nr_tests);
   if (test_is_dir_0 () == -1) {
     printf ("test_is_dir_0 FAILED\n");
     failed++;
   }
-  printf (" 37/ 49 test_is_dir_1\n");
+  printf (" 34/%3d test_is_dir_1\n", nr_tests);
   if (test_is_dir_1 () == -1) {
     printf ("test_is_dir_1 FAILED\n");
     failed++;
   }
-  printf (" 38/ 49 test_pvcreate_0\n");
+  printf (" 35/%3d test_pvcreate_0\n", nr_tests);
   if (test_pvcreate_0 () == -1) {
     printf ("test_pvcreate_0 FAILED\n");
     failed++;
   }
-  printf (" 39/ 49 test_vgcreate_0\n");
+  printf (" 36/%3d test_vgcreate_0\n", nr_tests);
   if (test_vgcreate_0 () == -1) {
     printf ("test_vgcreate_0 FAILED\n");
     failed++;
   }
-  printf (" 40/ 49 test_lvcreate_0\n");
+  printf (" 37/%3d test_lvcreate_0\n", nr_tests);
   if (test_lvcreate_0 () == -1) {
     printf ("test_lvcreate_0 FAILED\n");
     failed++;
   }
-  printf (" 41/ 49 test_mkfs_0\n");
+  printf (" 38/%3d test_mkfs_0\n", nr_tests);
   if (test_mkfs_0 () == -1) {
     printf ("test_mkfs_0 FAILED\n");
     failed++;
   }
-  printf (" 42/ 49 test_write_file_0\n");
+  printf (" 39/%3d test_write_file_0\n", nr_tests);
   if (test_write_file_0 () == -1) {
     printf ("test_write_file_0 FAILED\n");
     failed++;
   }
-  printf (" 43/ 49 test_umount_0\n");
+  printf (" 40/%3d test_umount_0\n", nr_tests);
   if (test_umount_0 () == -1) {
     printf ("test_umount_0 FAILED\n");
     failed++;
   }
-  printf (" 44/ 49 test_umount_1\n");
+  printf (" 41/%3d test_umount_1\n", nr_tests);
   if (test_umount_1 () == -1) {
     printf ("test_umount_1 FAILED\n");
     failed++;
   }
-  printf (" 45/ 49 test_mounts_0\n");
+  printf (" 42/%3d test_mounts_0\n", nr_tests);
   if (test_mounts_0 () == -1) {
     printf ("test_mounts_0 FAILED\n");
     failed++;
   }
-  printf (" 46/ 49 test_umount_all_0\n");
+  printf (" 43/%3d test_umount_all_0\n", nr_tests);
   if (test_umount_all_0 () == -1) {
     printf ("test_umount_all_0 FAILED\n");
     failed++;
   }
-  printf (" 47/ 49 test_file_0\n");
+  printf (" 44/%3d test_file_0\n", nr_tests);
   if (test_file_0 () == -1) {
     printf ("test_file_0 FAILED\n");
     failed++;
   }
-  printf (" 48/ 49 test_file_1\n");
+  printf (" 45/%3d test_file_1\n", nr_tests);
   if (test_file_1 () == -1) {
     printf ("test_file_1 FAILED\n");
     failed++;
   }
-  printf (" 49/ 49 test_file_2\n");
+  printf (" 46/%3d test_file_2\n", nr_tests);
   if (test_file_2 () == -1) {
     printf ("test_file_2 FAILED\n");
     failed++;
   }
+  printf (" 47/%3d test_stat_0\n", nr_tests);
+  if (test_stat_0 () == -1) {
+    printf ("test_stat_0 FAILED\n");
+    failed++;
+  }
+  printf (" 48/%3d test_lstat_0\n", nr_tests);
+  if (test_lstat_0 () == -1) {
+    printf ("test_lstat_0 FAILED\n");
+    failed++;
+  }
+  printf (" 49/%3d test_statvfs_0\n", nr_tests);
+  if (test_statvfs_0 () == -1) {
+    printf ("test_statvfs_0 FAILED\n");
+    failed++;
+  }
 
   guestfs_close (g);
   snprintf (buf, sizeof buf, "%s/test1.img", srcdir);
@@ -4155,7 +4076,7 @@ int main (int argc, char *argv[])
   unlink (buf);
 
   if (failed > 0) {
-    printf ("***** %d / 49 tests FAILED *****\n", failed);
+    printf ("***** %d / %d tests FAILED *****\n", failed, nr_tests);
     exit (1);
   }