ocaml/t/guestfs_005_load
ocaml/t/guestfs_010_launch
ocaml/t/guestfs_050_lvcreate
+ocaml/t/guestfs_060_readdir
perl/Guestfs.c
perl/Guestfs.bs
perl/Makefile-pl
fprintf (stderr, "warning: \"guestfs_df_h\" has no tests\n");
fprintf (stderr, "warning: \"guestfs_mount_loop\" has no tests\n");
fprintf (stderr, "warning: \"guestfs_umask\" has no tests\n");
+ fprintf (stderr, "warning: \"guestfs_readdir\" has no tests\n");
}
static int test_mknod_c_0_skip (void)
ntfs.c \
pingdaemon.c \
proto.c \
+ readdir.c \
scrub.c \
sfdisk.c \
sleep.c \
extern int do_mknod_b (int mode, int devmajor, int devminor, char *path);
extern int do_mknod_c (int mode, int devmajor, int devminor, char *path);
extern int do_umask (int mask);
+extern guestfs_int_dirent_list *do_readdir (char *dir);
--- /dev/null
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "daemon.h"
+#include "actions.h"
+
+guestfs_int_dirent_list *
+do_readdir (char *path)
+{
+ guestfs_int_dirent_list *ret;
+ guestfs_int_dirent v;
+ DIR *dir;
+ struct dirent *d;
+ int i;
+
+ NEED_ROOT (NULL);
+ ABS_PATH (path, NULL);
+
+ ret = malloc (sizeof *ret);
+ if (ret == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ret->guestfs_int_dirent_list_len = 0;
+ ret->guestfs_int_dirent_list_val = NULL;
+
+ CHROOT_IN;
+ dir = opendir (path);
+ CHROOT_OUT;
+
+ if (dir == NULL) {
+ reply_with_perror ("opendir: %s", path);
+ free (ret);
+ return NULL;
+ }
+
+ i = 0;
+ while ((d = readdir (dir)) != NULL) {
+ guestfs_int_dirent *p;
+
+ p = realloc (ret->guestfs_int_dirent_list_val,
+ sizeof (guestfs_int_dirent) * (i+1));
+ v.name = strdup (d->d_name);
+ if (!p || !v.name) {
+ reply_with_perror ("allocate");
+ free (ret->guestfs_int_dirent_list_val);
+ free (ret);
+ closedir (dir);
+ return NULL;
+ }
+ ret->guestfs_int_dirent_list_val = p;
+
+ v.ino = d->d_ino;
+ switch (d->d_type) {
+ case DT_BLK: v.ftyp = 'b'; break;
+ case DT_CHR: v.ftyp = 'c'; break;
+ case DT_DIR: v.ftyp = 'd'; break;
+ case DT_FIFO: v.ftyp = 'f'; break;
+ case DT_LNK: v.ftyp = 'l'; break;
+ case DT_REG: v.ftyp = 'r'; break;
+ case DT_SOCK: v.ftyp = 's'; break;
+ case DT_UNKNOWN: v.ftyp = 'u'; break;
+ default: v.ftyp = '?'; break;
+ }
+
+ ret->guestfs_int_dirent_list_val[i] = v;
+
+ i++;
+ }
+
+ ret->guestfs_int_dirent_list_len = i;
+
+ if (closedir (dir) == -1) {
+ reply_with_perror ("closedir");
+ free (ret->guestfs_int_dirent_list_val);
+ free (ret);
+ return NULL;
+ }
+
+ return ret;
+}
xdr_free ((xdrproc_t) xdr_guestfs_umask_args, (char *) &args);
}
+static void readdir_stub (XDR *xdr_in)
+{
+ guestfs_int_dirent_list *r;
+ struct guestfs_readdir_args args;
+ char *dir;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_readdir_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "readdir");
+ return;
+ }
+ dir = args.dir;
+
+ r = do_readdir (dir);
+ if (r == NULL)
+ /* do_readdir has already called reply_with_error */
+ goto done;
+
+ struct guestfs_readdir_ret ret;
+ ret.entries = *r;
+ reply ((xdrproc_t) xdr_guestfs_readdir_ret, (char *) &ret);
+ xdr_free ((xdrproc_t) xdr_guestfs_readdir_ret, (char *) &ret);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_readdir_args, (char *) &args);
+}
+
void dispatch_incoming_message (XDR *xdr_in)
{
switch (proc_nr) {
case GUESTFS_PROC_UMASK:
umask_stub (xdr_in);
break;
+ case GUESTFS_PROC_READDIR:
+ readdir_stub (xdr_in);
+ break;
default:
reply_with_error ("dispatch_incoming_message: unknown procedure number %d, set LIBGUESTFS_PATH to point to the matching libguestfs appliance directory", proc_nr);
}
printf ("%-20s %s\n", "pvs", "list the LVM physical volumes (PVs)");
printf ("%-20s %s\n", "pvs-full", "list the LVM physical volumes (PVs)");
printf ("%-20s %s\n", "read-lines", "read file as lines");
+ printf ("%-20s %s\n", "readdir", "read directories entries");
printf ("%-20s %s\n", "resize2fs", "resize an ext2/ext3 filesystem");
printf ("%-20s %s\n", "rm", "remove a file");
printf ("%-20s %s\n", "rm-rf", "remove a file or directory recursively");
if (strcasecmp (cmd, "umask") == 0)
pod2text ("umask - set file mode creation mask (umask)", " umask <mask>\n\nThis function sets the mask used for creating new files and\ndevice nodes to C<mask & 0777>.\n\nTypical umask values would be C<022> which creates new files\nwith permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and\nC<002> which creates new files with permissions like\n\"-rw-rw-r--\" or \"-rwxrwxr-x\".\n\nThe default umask is C<022>. This is important because it\nmeans that directories and device nodes will be created with\nC<0644> or C<0755> mode even if you specify C<0777>.\n\nSee also L<umask(2)>, C<mknod>, C<mkdir>.\n\nThis call returns the previous umask.");
else
+ if (strcasecmp (cmd, "readdir") == 0)
+ pod2text ("readdir - read directories entries", " readdir <dir>\n\nThis returns the list of directory entries in directory C<dir>.\n\nAll entries in the directory are returned, including C<.> and\nC<..>. The entries are I<not> sorted, but returned in the same\norder as the underlying filesystem.\n\nThis function is primarily intended for use by programs. To\nget a simple list of names, use C<ls>. To get a printable\ndirectory for human consumption, use C<ll>.");
+ else
display_builtin_command (cmd);
}
printf ("namemax: %" PRIi64 "\n", statvfs->namemax);
}
+static void print_dirent (struct guestfs_dirent *dirent)
+{
+ printf ("ino: %" PRIi64 "\n", dirent->ino);
+ printf ("ftyp: %c\n", dirent->ftyp);
+ printf ("name: %s\n", dirent->name);
+}
+
+static void print_dirent_list (struct guestfs_dirent_list *dirents)
+{
+ int i;
+
+ for (i = 0; i < dirents->len; ++i)
+ print_dirent (&dirents->val[i]);
+}
+
static int run_launch (const char *cmd, int argc, char *argv[])
{
int r;
return 0;
}
+static int run_readdir (const char *cmd, int argc, char *argv[])
+{
+ struct guestfs_dirent_list *r;
+ const char *dir;
+ 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;
+ }
+ dir = argv[0];
+ r = guestfs_readdir (g, dir);
+ if (r == NULL) return -1;
+ print_dirent_list (r);
+ guestfs_free_dirent_list (r);
+ return 0;
+}
+
int run_action (const char *cmd, int argc, char *argv[])
{
if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
if (strcasecmp (cmd, "umask") == 0)
return run_umask (cmd, argc, argv);
else
+ if (strcasecmp (cmd, "readdir") == 0)
+ return run_readdir (cmd, argc, argv);
+ else
{
fprintf (stderr, "%s: unknown command\n", cmd);
return -1;
"mknod-b",
"mknod-c",
"umask",
+ "readdir",
NULL
};
as end of line). For those you need to use the C<read-file>
function which has a more complex interface.
+=head2 readdir
+
+ readdir dir
+
+This returns the list of directory entries in directory C<dir>.
+
+All entries in the directory are returned, including C<.> and
+C<..>. The entries are I<not> sorted, but returned in the same
+order as the underlying filesystem.
+
+This function is primarily intended for use by programs. To
+get a simple list of names, use C<ls>. To get a printable
+directory for human consumption, use C<ll>.
+
=head2 resize2fs
resize2fs device
(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_readdir
+
+ struct guestfs_dirent_list *guestfs_readdir (guestfs_h *handle,
+ const char *dir);
+
+This returns the list of directory entries in directory C<dir>.
+
+All entries in the directory are returned, including C<.> and
+C<..>. The entries are I<not> sorted, but returned in the same
+order as the underlying filesystem.
+
+This function is primarily intended for use by programs. To
+get a simple list of names, use C<guestfs_ls>. To get a printable
+directory for human consumption, use C<guestfs_ll>.
+
+This function returns a C<struct guestfs_dirent_list *>
+(see E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
+I<The caller must call C<guestfs_free_dirent_list> after use>.
+
=head2 guestfs_resize2fs
int guestfs_resize2fs (guestfs_h *handle,
void guestfs_free_lvm_lv_list (struct guestfs_free_lvm_lv_list *);
+=head2 guestfs_stat
+
+ 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;
+ };
+
+=head2 guestfs_statvfs
+
+ 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;
+ };
+
+=head2 guestfs_dirent
+
+ struct guestfs_dirent {
+ int64_t ino;
+ char ftyp;
+ char *name;
+ };
+
+ struct guestfs_dirent_list {
+ uint32_t len; /* Number of elements in list. */
+ struct guestfs_dirent *val; /* Elements. */
+ };
+
+ void guestfs_free_dirent_list (struct guestfs_free_dirent_list *);
+
$(CPTH)/LV.java \
$(CPTH)/Stat.java \
$(CPTH)/StatVFS.java \
+ $(CPTH)/Dirent.java \
$(CPTH)/GuestFS.java
java_tests = \
--- /dev/null
+/* libguestfs generated file
+ * WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.
+ * ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package com.redhat.et.libguestfs;
+
+/**
+ * Libguestfs Dirent structure.
+ *
+ * @author rjones
+ * @see GuestFS
+ */
+public class Dirent {
+ public long ino;
+ public char ftyp;
+ public String name;
+}
import com.redhat.et.libguestfs.Stat;
import com.redhat.et.libguestfs.StatVFS;
import com.redhat.et.libguestfs.IntBool;
+import com.redhat.et.libguestfs.Dirent;
/**
* The GuestFS object is a libguestfs handle.
private native int _umask (long g, int mask)
throws LibGuestFSException;
+ /**
+ * read directories entries
+ * <p>
+ * This returns the list of directory entries in directory
+ * "dir".
+ * <p>
+ * All entries in the directory are returned, including "."
+ * and "..". The entries are *not* sorted, but returned in
+ * the same order as the underlying filesystem.
+ * <p>
+ * This function is primarily intended for use by programs.
+ * To get a simple list of names, use "g.ls". To get a
+ * printable directory for human consumption, use "g.ll".
+ * <p>
+ * @throws LibGuestFSException
+ */
+ public Dirent[] readdir (String dir)
+ throws LibGuestFSException
+ {
+ if (g == 0)
+ throw new LibGuestFSException ("readdir: handle is closed");
+ return _readdir (g, dir);
+ }
+ private native Dirent[] _readdir (long g, String dir)
+ throws LibGuestFSException;
+
}
return (jint) r;
}
+JNIEXPORT jobjectArray JNICALL
+Java_com_redhat_et_libguestfs_GuestFS__1readdir
+ (JNIEnv *env, jobject obj, jlong jg, jstring jdir)
+{
+ guestfs_h *g = (guestfs_h *) (long) jg;
+ jobjectArray jr;
+ jclass cl;
+ jfieldID fl;
+ jobject jfl;
+ struct guestfs_dirent_list *r;
+ const char *dir;
+ int i;
+
+ dir = (*env)->GetStringUTFChars (env, jdir, NULL);
+ r = guestfs_readdir (g, dir);
+ (*env)->ReleaseStringUTFChars (env, jdir, dir);
+ if (r == NULL) {
+ throw_exception (env, guestfs_last_error (g));
+ return NULL;
+ }
+ cl = (*env)->FindClass (env, "com/redhat/et/libguestfs/Dirent");
+ jr = (*env)->NewObjectArray (env, r->len, cl, NULL);
+ for (i = 0; i < r->len; ++i) {
+ jfl = (*env)->AllocObject (env, cl);
+ fl = (*env)->GetFieldID (env, cl, "ino", "J");
+ (*env)->SetLongField (env, jfl, fl, r->val[i].ino);
+ fl = (*env)->GetFieldID (env, cl, "ftyp", "J");
+ (*env)->SetLongField (env, jfl, fl, r->val[i].ftyp);
+ fl = (*env)->GetFieldID (env, cl, "name", "Ljava/lang/String;");
+ (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].name));
+ (*env)->SetObjectArrayElement (env, jfl, i, jfl);
+ }
+ guestfs_free_dirent_list (r);
+ return jr;
+}
+
$(VG)
TESTS = run-bindtests \
- t/guestfs_005_load t/guestfs_010_launch t/guestfs_050_lvcreate
+ t/guestfs_005_load t/guestfs_010_launch t/guestfs_050_lvcreate \
+ t/guestfs_060_readdir
noinst_DATA += bindtests \
- t/guestfs_005_load t/guestfs_010_launch t/guestfs_050_lvcreate
+ t/guestfs_005_load t/guestfs_010_launch t/guestfs_050_lvcreate \
+ t/guestfs_060_readdir
bindtests: bindtests.ml mlguestfs.cmxa
$(OCAMLFIND) ocamlopt -cclib -L$(top_builddir)/src/.libs -I . unix.cmxa mlguestfs.cmxa $< -o $@
t/guestfs_050_lvcreate: t/guestfs_050_lvcreate.ml mlguestfs.cmxa
$(OCAMLFIND) ocamlopt -cclib -L$(top_builddir)/src/.libs -I . unix.cmxa mlguestfs.cmxa $< -o $@
+t/guestfs_060_readdir: t/guestfs_060_readdir.ml mlguestfs.cmxa
+ $(OCAMLFIND) ocamlopt -cclib -L$(top_builddir)/src/.libs -I . unix.cmxa mlguestfs.cmxa $< -o $@
+
.mli.cmi:
$(OCAMLFIND) ocamlc -c $<
.ml.cmo:
namemax : int64;
}
+type dirent = {
+ ino : int64;
+ ftyp : char;
+ name : string;
+}
+
external test0 : t -> string -> string option -> string array -> bool -> int -> string -> string -> unit = "ocaml_guestfs_test0_byte" "ocaml_guestfs_test0"
external test0rint : t -> string -> int = "ocaml_guestfs_test0rint"
external test0rinterr : t -> int = "ocaml_guestfs_test0rinterr"
external mknod_b : t -> int -> int -> int -> string -> unit = "ocaml_guestfs_mknod_b"
external mknod_c : t -> int -> int -> int -> string -> unit = "ocaml_guestfs_mknod_c"
external umask : t -> int -> int = "ocaml_guestfs_umask"
+external readdir : t -> string -> dirent array = "ocaml_guestfs_readdir"
namemax : int64;
}
+type dirent = {
+ ino : int64;
+ ftyp : char;
+ name : string;
+}
+
val test0 : t -> string -> string option -> string array -> bool -> int -> string -> string -> unit
(** internal test function - do not use *)
val umask : t -> int -> int
(** set file mode creation mask (umask) *)
+val readdir : t -> string -> dirent array
+(** read directories entries *)
+
CAMLreturn (rv);
}
+static CAMLprim value
+copy_dirent (const struct guestfs_dirent *dirent)
+{
+ CAMLparam0 ();
+ CAMLlocal2 (rv, v);
+
+ rv = caml_alloc (3, 0);
+ v = caml_copy_int64 (dirent->ino);
+ Store_field (rv, 0, v);
+ v = Val_int (dirent->ftyp);
+ Store_field (rv, 1, v);
+ v = caml_copy_string (dirent->name);
+ Store_field (rv, 2, v);
+ CAMLreturn (rv);
+}
+
+static CAMLprim value
+copy_dirent_list (const struct guestfs_dirent_list *dirents)
+{
+ CAMLparam0 ();
+ CAMLlocal2 (rv, v);
+ int i;
+
+ if (dirents->len == 0)
+ CAMLreturn (Atom (0));
+ else {
+ rv = caml_alloc (dirents->len, 0);
+ for (i = 0; i < dirents->len; ++i) {
+ v = copy_dirent (&dirents->val[i]);
+ caml_modify (&Field (rv, i), v);
+ }
+ CAMLreturn (rv);
+ }
+}
+
CAMLprim value
ocaml_guestfs_test0 (value gv, value strv, value optstrv, value strlistv, value bv, value integerv, value fileinv, value fileoutv)
{
CAMLreturn (rv);
}
+CAMLprim value
+ocaml_guestfs_readdir (value gv, value dirv)
+{
+ CAMLparam2 (gv, dirv);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("readdir: used handle after closing it");
+
+ const char *dir = String_val (dirv);
+ struct guestfs_dirent_list *r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_readdir (g, dir);
+ caml_leave_blocking_section ();
+ if (r == NULL)
+ ocaml_guestfs_raise_error (g, "readdir");
+
+ rv = copy_dirent_list (r);
+ guestfs_free_dirent_list (r);
+ CAMLreturn (rv);
+}
+
--- /dev/null
+(* libguestfs OCaml bindings
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *)
+
+open Unix
+
+let () =
+ let g = Guestfs.create () in
+
+ let fd = openfile "test.img" [O_WRONLY;O_CREAT;O_NOCTTY;O_TRUNC] 0o666 in
+ ftruncate fd (10 * 1024 * 1024);
+ close fd;
+
+ Guestfs.add_drive g "test.img";
+ Guestfs.launch g;
+ Guestfs.wait_ready g;
+
+ Guestfs.sfdisk g "/dev/sda" 0 0 0 [|","|];
+ Guestfs.mkfs g "ext2" "/dev/sda1";
+ Guestfs.mount g "/dev/sda1" "/";
+ Guestfs.mkdir g "/p";
+ Guestfs.touch g "/q";
+
+ let dirs = Guestfs.readdir g "/" in
+ let dirs = Array.to_list dirs in
+ let cmp { Guestfs.name = n1 } { Guestfs.name = n2 } = compare n1 n2 in
+ let dirs = List.sort cmp dirs in
+ let dirs = List.map (
+ fun { Guestfs.name = name; Guestfs.ftyp = ftyp } -> (name, ftyp)
+ ) dirs in
+
+ if dirs <> [ ".", 'd';
+ "..", 'd';
+ "lost+found", 'd';
+ "p", 'd';
+ "q", 'r' ] then
+ failwith "Guestfs.readdir returned incorrect result";
+
+ Guestfs.close g;
+ unlink "test.img"
(void) hv_store (hv, "pe_start", 8, my_newSVull (valout->val[i].pe_start), 0);
(void) hv_store (hv, "pv_mda_count", 12, my_newSVll (valout->val[i].pv_mda_count), 0);
(void) hv_store (hv, "pv_mda_free", 11, my_newSVull (valout->val[i].pv_mda_free), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_pv_list (valout);
(void) hv_store (hv, "pe_start", 8, my_newSVull (valout->val[i].pe_start), 0);
(void) hv_store (hv, "pv_mda_count", 12, my_newSVll (valout->val[i].pv_mda_count), 0);
(void) hv_store (hv, "pv_mda_free", 11, my_newSVull (valout->val[i].pv_mda_free), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_pv_list (valout);
(void) hv_store (hv, "vg_tags", 7, newSVpv (valout->val[i].vg_tags, 0), 0);
(void) hv_store (hv, "vg_mda_count", 12, my_newSVll (valout->val[i].vg_mda_count), 0);
(void) hv_store (hv, "vg_mda_free", 11, my_newSVull (valout->val[i].vg_mda_free), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_vg_list (valout);
(void) hv_store (hv, "vg_tags", 7, newSVpv (valout->val[i].vg_tags, 0), 0);
(void) hv_store (hv, "vg_mda_count", 12, my_newSVll (valout->val[i].vg_mda_count), 0);
(void) hv_store (hv, "vg_mda_free", 11, my_newSVull (valout->val[i].vg_mda_free), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_vg_list (valout);
(void) hv_store (hv, "lv_tags", 7, newSVpv (valout->val[i].lv_tags, 0), 0);
(void) hv_store (hv, "mirror_log", 10, newSVpv (valout->val[i].mirror_log, 0), 0);
(void) hv_store (hv, "modules", 7, newSVpv (valout->val[i].modules, 0), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_lv_list (valout);
(void) hv_store (hv, "lv_tags", 7, newSVpv (valout->val[i].lv_tags, 0), 0);
(void) hv_store (hv, "mirror_log", 10, newSVpv (valout->val[i].mirror_log, 0), 0);
(void) hv_store (hv, "modules", 7, newSVpv (valout->val[i].modules, 0), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_lv_list (valout);
(void) hv_store (hv, "pe_start", 8, my_newSVull (physvols->val[i].pe_start), 0);
(void) hv_store (hv, "pv_mda_count", 12, my_newSVll (physvols->val[i].pv_mda_count), 0);
(void) hv_store (hv, "pv_mda_free", 11, my_newSVull (physvols->val[i].pv_mda_free), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_pv_list (physvols);
(void) hv_store (hv, "vg_tags", 7, newSVpv (volgroups->val[i].vg_tags, 0), 0);
(void) hv_store (hv, "vg_mda_count", 12, my_newSVll (volgroups->val[i].vg_mda_count), 0);
(void) hv_store (hv, "vg_mda_free", 11, my_newSVull (volgroups->val[i].vg_mda_free), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_vg_list (volgroups);
(void) hv_store (hv, "lv_tags", 7, newSVpv (logvols->val[i].lv_tags, 0), 0);
(void) hv_store (hv, "mirror_log", 10, newSVpv (logvols->val[i].mirror_log, 0), 0);
(void) hv_store (hv, "modules", 7, newSVpv (logvols->val[i].modules, 0), 0);
- PUSHs (sv_2mortal ((SV *) hv));
+ PUSHs (sv_2mortal (newRV ((SV *) hv)));
}
guestfs_free_lvm_lv_list (logvols);
OUTPUT:
RETVAL
+void
+readdir (g, dir)
+ guestfs_h *g;
+ char *dir;
+PREINIT:
+ struct guestfs_dirent_list *entries;
+ int i;
+ HV *hv;
+ PPCODE:
+ entries = guestfs_readdir (g, dir);
+ if (entries == NULL)
+ croak ("readdir: %s", guestfs_last_error (g));
+ EXTEND (SP, entries->len);
+ for (i = 0; i < entries->len; ++i) {
+ hv = newHV ();
+ (void) hv_store (hv, "ino", 3, my_newSVull (entries->val[i].ino), 0);
+ (void) hv_store (hv, "ftyp", 4, newSVpv (&entries->val[i].ftyp, 1), 0);
+ (void) hv_store (hv, "name", 4, newSVpv (entries->val[i].name, 0), 0);
+ PUSHs (newRV (sv_2mortal ((SV *) hv)));
+ }
+ guestfs_free_dirent_list (entries);
+
as end of line). For those you need to use the C<$h-E<gt>read_file>
function which has a more complex interface.
+=item @entries = $h->readdir ($dir);
+
+This returns the list of directory entries in directory C<dir>.
+
+All entries in the directory are returned, including C<.> and
+C<..>. The entries are I<not> sorted, but returned in the same
+order as the underlying filesystem.
+
+This function is primarily intended for use by programs. To
+get a simple list of names, use C<$h-E<gt>ls>. To get a printable
+directory for human consumption, use C<$h-E<gt>ll>.
+
=item $h->resize2fs ($device);
This resizes an ext2 or ext3 filesystem to match the size of
--- /dev/null
+# libguestfs Perl bindings -*- perl -*-
+# Copyright (C) 2009 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+use Test::More tests => 13;
+
+use Sys::Guestfs;
+
+my $h = Sys::Guestfs->new ();
+ok ($h);
+open FILE, ">test.img";
+truncate FILE, 10*1024*1024;
+close FILE;
+ok (1);
+
+$h->add_drive ("test.img");
+ok (1);
+
+$h->launch ();
+ok (1);
+$h->wait_ready ();
+ok (1);
+
+$h->sfdisk ("/dev/sda", 0, 0, 0, [","]);
+ok (1);
+$h->mkfs ("ext2", "/dev/sda1");
+ok (1);
+$h->mount ("/dev/sda1", "/");
+ok (1);
+$h->mkdir ("/p");
+ok (1);
+$h->touch ("/q");
+ok (1);
+
+my @dirs = $h->readdir ("/");
+@dirs = sort { $a->{name} cmp $b->{name} } @dirs;
+foreach (@dirs) {
+ print "$_->{name} $_->{ino} $_->{ftyp}\n";
+}
+ok (1);
+
+$h->sync ();
+ok (1);
+
+undef $h;
+ok (1);
+
+unlink ("test.img");
};
static PyObject *
+put_dirent (struct guestfs_dirent *dirent)
+{
+ PyObject *dict;
+
+ dict = PyDict_New ();
+ PyDict_SetItemString (dict, "ino",
+ PyLong_FromLongLong (dirent->ino));
+ PyDict_SetItemString (dict, "ftyp",
+ PyString_FromStringAndSize (&dirent->ftyp, 1));
+ PyDict_SetItemString (dict, "name",
+ PyString_FromString (dirent->name));
+ return dict;
+};
+
+static PyObject *
+put_dirent_list (struct guestfs_dirent_list *dirents)
+{
+ PyObject *list;
+ int i;
+
+ list = PyList_New (dirents->len);
+ for (i = 0; i < dirents->len; ++i)
+ PyList_SetItem (list, i, put_dirent (&dirents->val[i]));
+ return list;
+};
+
+static PyObject *
py_guestfs_test0 (PyObject *self, PyObject *args)
{
PyObject *py_g;
return py_r;
}
+static PyObject *
+py_guestfs_readdir (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ struct guestfs_dirent_list *r;
+ const char *dir;
+
+ if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_readdir",
+ &py_g, &dir))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_readdir (g, dir);
+ if (r == NULL) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ py_r = put_dirent_list (r);
+ guestfs_free_dirent_list (r);
+ return py_r;
+}
+
static PyMethodDef methods[] = {
{ (char *) "create", py_guestfs_create, METH_VARARGS, NULL },
{ (char *) "close", py_guestfs_close, METH_VARARGS, NULL },
{ (char *) "mknod_b", py_guestfs_mknod_b, METH_VARARGS, NULL },
{ (char *) "mknod_c", py_guestfs_mknod_c, METH_VARARGS, NULL },
{ (char *) "umask", py_guestfs_umask, METH_VARARGS, NULL },
+ { (char *) "readdir", py_guestfs_readdir, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
"""
return libguestfsmod.umask (self._o, mask)
+ def readdir (self, dir):
+ u"""This returns the list of directory entries in directory
+ "dir".
+
+ All entries in the directory are returned, including "."
+ and "..". The entries are *not* sorted, but returned in
+ the same order as the underlying filesystem.
+
+ This function is primarily intended for use by programs.
+ To get a simple list of names, use "g.ls". To get a
+ printable directory for human consumption, use "g.ll".
+
+ This function returns a list of directory entries. Each
+ directory entry is represented as a dictionary.
+ """
+ return libguestfsmod.readdir (self._o, dir)
+
return INT2NUM (r);
}
+static VALUE ruby_guestfs_readdir (VALUE gv, VALUE dirv)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "readdir");
+
+ Check_Type (dirv, T_STRING);
+ const char *dir = StringValueCStr (dirv);
+ if (!dir)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "dir", "readdir");
+
+ struct guestfs_dirent_list *r;
+
+ r = guestfs_readdir (g, dir);
+ if (r == NULL)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ VALUE rv = rb_ary_new2 (r->len);
+ int i;
+ for (i = 0; i < r->len; ++i) {
+ VALUE hv = rb_hash_new ();
+ rb_hash_aset (rv, rb_str_new2 ("ino"), ULL2NUM (r->val[i].ino));
+ rb_hash_aset (rv, rb_str_new2 ("ftyp"), ULL2NUM (r->val[i].ftyp));
+ rb_hash_aset (rv, rb_str_new2 ("name"), rb_str_new2 (r->val[i].name));
+ rb_ary_push (rv, hv);
+ }
+ guestfs_free_dirent_list (r);
+ return rv;
+}
+
/* Initialize the module. */
void Init__guestfs ()
{
ruby_guestfs_mknod_c, 4);
rb_define_method (c_guestfs, "umask",
ruby_guestfs_umask, 1);
+ rb_define_method (c_guestfs, "readdir",
+ ruby_guestfs_readdir, 1);
}
* inefficient. Keys should be unique. NULLs are not permitted.
*)
| RHashtable of string
+ (* List of directory entries (the result of readdir(3)). *)
+ | RDirentList of string
and args = argt list (* Function parameters, guestfs handle is implicit. *)
This call returns the previous umask.");
+ ("readdir", (RDirentList "entries", [String "dir"]), 138, [],
+ [],
+ "read directories entries",
+ "\
+This returns the list of directory entries in directory C<dir>.
+
+All entries in the directory are returned, including C<.> and
+C<..>. The entries are I<not> sorted, but returned in the same
+order as the underlying filesystem.
+
+This function is primarily intended for use by programs. To
+get a simple list of names, use C<guestfs_ls>. To get a printable
+directory for human consumption, use C<guestfs_ll>.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
"namemax", `Int;
]
+(* Column names in dirent structure. *)
+let dirent_cols = [
+ "ino", `Int;
+ "ftyp", `Char; (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
+ "name", `String;
+]
+
(* Used for testing language bindings. *)
type callt =
| CallString of string
| RInt n | RInt64 n | RBool n | RConstString n | RString n
| RStringList n | RPVList n | RVGList n | RLVList n
| RStat n | RStatVFS n
- | RHashtable n ->
+ | RHashtable n
+ | RDirentList n ->
check_arg_ret_name n
| RIntBool (n,m) ->
check_arg_ret_name n;
The array of strings will always have length C<2n+1>, where
C<n> keys and values alternate, followed by the trailing NULL entry.
I<The caller must free the strings and the array after use>.\n\n"
+ | RDirentList _ ->
+ pr "This function returns a C<struct guestfs_dirent_list *>
+(see E<lt>guestfs-structs.hE<gt>),
+or NULL if there was an error.
+I<The caller must call C<guestfs_free_dirent_list> after use>.\n\n"
);
if List.mem ProtocolLimitWarning flags then
pr "%s\n\n" protocol_limit_warning;
pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
typ typ;
pr "\n"
- ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
+ ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
+
+ (* Stat *)
+ List.iter (
+ fun (typ, cols) ->
+ pr "=head2 guestfs_%s\n" typ;
+ pr "\n";
+ pr " struct guestfs_%s {\n" typ;
+ List.iter (
+ function
+ | name, `Int -> pr " int64_t %s;\n" name
+ ) cols;
+ pr " };\n";
+ pr "\n";
+ ) [ "stat", stat_cols; "statvfs", statvfs_cols ];
+
+ (* DirentList *)
+ pr "=head2 guestfs_dirent\n";
+ pr "\n";
+ pr " struct guestfs_dirent {\n";
+ List.iter (
+ function
+ | name, `String -> pr " char *%s;\n" name
+ | name, `Int -> pr " int64_t %s;\n" name
+ | name, `Char -> pr " char %s;\n" name
+ ) dirent_cols;
+ pr " };\n";
+ pr "\n";
+ pr " struct guestfs_dirent_list {\n";
+ pr " uint32_t len; /* Number of elements in list. */\n";
+ pr " struct guestfs_dirent *val; /* Elements. */\n";
+ pr " };\n";
+ pr " \n";
+ pr " void guestfs_free_dirent_list (struct guestfs_free_dirent_list *);\n";
+ pr "\n"
(* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
* indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
pr "\n";
) ["stat", stat_cols; "statvfs", statvfs_cols];
+ (* Dirent structures. *)
+ pr "struct guestfs_int_dirent {\n";
+ List.iter (function
+ | name, `Int -> pr " hyper %s;\n" name
+ | name, `Char -> pr " char %s;\n" name
+ | name, `String -> pr " string %s<>;\n" name
+ ) dirent_cols;
+ pr "};\n";
+ pr "\n";
+ pr "typedef struct guestfs_int_dirent guestfs_int_dirent_list<>;\n";
+ pr "\n";
+
List.iter (
fun (shortname, style, _, _, _, _, _) ->
let name = "guestfs_" ^ shortname in
pr "struct %s_ret {\n" name;
pr " str %s<>;\n" n;
pr "};\n\n"
+ | RDirentList n ->
+ pr "struct %s_ret {\n" name;
+ pr " guestfs_int_dirent_list %s;\n" n;
+ pr "};\n\n"
);
) daemon_functions;
) cols;
pr "};\n";
pr "\n"
- ) ["stat", stat_cols; "statvfs", statvfs_cols]
+ ) ["stat", stat_cols; "statvfs", statvfs_cols];
+
+ (* Dirent structures. *)
+ pr "struct guestfs_dirent {\n";
+ List.iter (
+ function
+ | name, `Int -> pr " int64_t %s;\n" name
+ | name, `Char -> pr " char %s;\n" name
+ | name, `String -> pr " char *%s;\n" name
+ ) dirent_cols;
+ pr "};\n";
+ pr "\n";
+ pr "struct guestfs_dirent_list {\n";
+ pr " uint32_t len;\n";
+ pr " struct guestfs_dirent *val;\n";
+ pr "};\n";
+ pr "\n"
(* Generate the guestfs-actions.h file. *)
and generate_actions_h () =
| RIntBool _
| RPVList _ | RVGList _ | RLVList _
| RStat _ | RStatVFS _
- | RHashtable _ ->
+ | RHashtable _
+ | RDirentList _ ->
pr " struct %s_ret ret;\n" name
);
pr "};\n";
| RIntBool _
| RPVList _ | RVGList _ | RLVList _
| RStat _ | RStatVFS _
- | RHashtable _ ->
+ | RHashtable _
+ | RDirentList _ ->
pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
pr " return;\n";
| RString _ | RStringList _ | RIntBool _
| RPVList _ | RVGList _ | RLVList _
| RStat _ | RStatVFS _
- | RHashtable _ ->
+ | RHashtable _
+ | RDirentList _ ->
"NULL" in
pr "{\n";
pr " /* caller with free this */\n";
pr " return safe_memdup (g, &ctx.ret, sizeof (ctx.ret));\n"
| RPVList n | RVGList n | RLVList n
- | RStat n | RStatVFS n ->
+ | RStat n | RStatVFS n
+ | RDirentList n ->
pr " /* caller will free this */\n";
pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
);
| RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
| RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
| RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
- | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
+ | RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL"
+ | RDirentList _ -> pr " guestfs_int_dirent_list *r;\n"; "NULL" in
(match snd style with
| [] -> ()
name;
pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
| RPVList n | RVGList n | RLVList n
- | RStat n | RStatVFS n ->
+ | RStat n | RStatVFS n
+ | RDirentList n ->
pr " struct guestfs_%s_ret ret;\n" name;
pr " ret.%s = *r;\n" n;
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
| RStat _ ->
pr " struct guestfs_stat *r;\n"; "NULL"
| RStatVFS _ ->
- pr " struct guestfs_statvfs *r;\n"; "NULL" in
+ pr " struct guestfs_statvfs *r;\n"; "NULL"
+ | RDirentList _ ->
+ pr " struct guestfs_dirent_list *r;\n"; "NULL" in
pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
pr " r = guestfs_%s (g" name;
pr " guestfs_free_lvm_lv_list (r);\n"
| RStat _ | RStatVFS _ ->
pr " free (r);\n"
+ | RDirentList _ ->
+ pr " guestfs_free_dirent_list (r);\n"
);
pr " }\n"
pr "\n";
) ["stat", stat_cols; "statvfs", statvfs_cols];
+ (* print_dirent_list function *)
+ pr "static void print_dirent (struct guestfs_dirent *dirent)\n";
+ pr "{\n";
+ List.iter (
+ function
+ | name, `String ->
+ pr " printf (\"%s: %%s\\n\", dirent->%s);\n" name name
+ | name, `Int ->
+ pr " printf (\"%s: %%\" PRIi64 \"\\n\", dirent->%s);\n" name name
+ | name, `Char ->
+ pr " printf (\"%s: %%c\\n\", dirent->%s);\n" name name
+ ) dirent_cols;
+ pr "}\n";
+ pr "\n";
+ pr "static void print_dirent_list (struct guestfs_dirent_list *dirents)\n";
+ pr "{\n";
+ pr " int i;\n";
+ pr "\n";
+ pr " for (i = 0; i < dirents->len; ++i)\n";
+ pr " print_dirent (&dirents->val[i]);\n";
+ pr "}\n";
+ pr "\n";
+
(* run_<action> actions *)
List.iter (
fun (name, style, _, flags, _, _, _) ->
| RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
| RStat _ -> pr " struct guestfs_stat *r;\n"
| RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
+ | RDirentList _ -> pr " struct guestfs_dirent_list *r;\n"
);
List.iter (
function
pr " print_table (r);\n";
pr " free_strings (r);\n";
pr " return 0;\n"
+ | RDirentList _ ->
+ pr " if (r == NULL) return -1;\n";
+ pr " print_dirent_list (r);\n";
+ pr " guestfs_free_dirent_list (r);\n";
+ pr " return 0;\n"
);
pr "}\n";
pr "\n"
| RStatVFS _ ->
if not in_daemon then pr "struct guestfs_statvfs *"
else pr "guestfs_int_statvfs *"
+ | RDirentList _ ->
+ if not in_daemon then pr "struct guestfs_dirent_list *"
+ else pr "guestfs_int_dirent_list *"
);
pr "%s%s (" prefix name;
if handle = None && List.length (snd style) = 0 then
generate_ocaml_stat_structure_decls ();
+ generate_ocaml_dirent_structure_decls ();
+
(* The actions. *)
List.iter (
fun (name, style, _, _, _, shortdesc, _) ->
generate_ocaml_stat_structure_decls ();
+ generate_ocaml_dirent_structure_decls ();
+
(* The actions. *)
List.iter (
fun (name, style, _, _, _, shortdesc, _) ->
pr "\n";
) ["stat", stat_cols; "statvfs", statvfs_cols];
+ (* Dirent copy functions. *)
+ pr "static CAMLprim value\n";
+ pr "copy_dirent (const struct guestfs_dirent *dirent)\n";
+ pr "{\n";
+ pr " CAMLparam0 ();\n";
+ pr " CAMLlocal2 (rv, v);\n";
+ pr "\n";
+ pr " rv = caml_alloc (%d, 0);\n" (List.length dirent_cols);
+ iteri (
+ fun i col ->
+ (match col with
+ | name, `String ->
+ pr " v = caml_copy_string (dirent->%s);\n" name
+ | name, `Int ->
+ pr " v = caml_copy_int64 (dirent->%s);\n" name
+ | name, `Char ->
+ pr " v = Val_int (dirent->%s);\n" name
+ );
+ pr " Store_field (rv, %d, v);\n" i
+ ) dirent_cols;
+ pr " CAMLreturn (rv);\n";
+ pr "}\n";
+ pr "\n";
+
+ pr "static CAMLprim value\n";
+ pr "copy_dirent_list (const struct guestfs_dirent_list *dirents)\n";
+ pr "{\n";
+ pr " CAMLparam0 ();\n";
+ pr " CAMLlocal2 (rv, v);\n";
+ pr " int i;\n";
+ pr "\n";
+ pr " if (dirents->len == 0)\n";
+ pr " CAMLreturn (Atom (0));\n";
+ pr " else {\n";
+ pr " rv = caml_alloc (dirents->len, 0);\n";
+ pr " for (i = 0; i < dirents->len; ++i) {\n";
+ pr " v = copy_dirent (&dirents->val[i]);\n";
+ pr " caml_modify (&Field (rv, i), v);\n";
+ pr " }\n";
+ pr " CAMLreturn (rv);\n";
+ pr " }\n";
+ pr "}\n";
+ pr "\n";
+
(* The wrappers. *)
List.iter (
fun (name, style, _, _, _, _, _) ->
| RHashtable _ ->
pr " int i;\n";
pr " char **r;\n";
- "NULL" in
+ "NULL"
+ | RDirentList _ ->
+ pr " struct guestfs_dirent_list *r;\n"; "NULL" in
pr "\n";
pr " caml_enter_blocking_section ();\n";
pr " rv = copy_table (r);\n";
pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
pr " free (r);\n";
+ | RDirentList _ ->
+ pr " rv = copy_dirent_list (r);\n";
+ pr " guestfs_free_dirent_list (r);\n";
);
pr " CAMLreturn (rv);\n";
pr "\n"
) ["stat", stat_cols; "statvfs", statvfs_cols]
+and generate_ocaml_dirent_structure_decls () =
+ pr "type dirent = {\n";
+ List.iter (
+ function
+ | name, `Int -> pr " %s : int64;\n" name
+ | name, `Char -> pr " %s : char;\n" name
+ | name, `String -> pr " %s : string;\n" name
+ ) dirent_cols;
+ pr "}\n";
+ pr "\n"
+
and generate_ocaml_prototype ?(is_external = false) name style =
if is_external then pr "external " else pr "val ";
pr "%s : t -> " name;
| RStat _ -> pr "stat"
| RStatVFS _ -> pr "statvfs"
| RHashtable _ -> pr "(string * string) list"
+ | RDirentList _ -> pr "dirent array"
);
if is_external then (
pr " = ";
| RIntBool _
| RPVList _ | RVGList _ | RLVList _
| RStat _ | RStatVFS _
- | RHashtable _ ->
+ | RHashtable _
+ | RDirentList _ ->
pr "void\n" (* all lists returned implictly on the stack *)
);
(* Call and arguments. *)
| RStatVFS n ->
generate_perl_stat_code
"statvfs" statvfs_cols name style n do_cleanups
+ | RDirentList n ->
+ generate_perl_dirent_code
+ "dirent" dirent_cols name style n do_cleanups
);
pr "\n"
pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
name (String.length name) n name
) cols;
- pr " PUSHs (sv_2mortal ((SV *) hv));\n";
+ pr " PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
pr " }\n";
pr " guestfs_free_lvm_%s_list (%s);\n" typ n
) cols;
pr " free (%s);\n" n
+and generate_perl_dirent_code typ cols name style n do_cleanups =
+ pr "PREINIT:\n";
+ pr " struct guestfs_%s_list *%s;\n" typ n;
+ pr " int i;\n";
+ pr " HV *hv;\n";
+ pr " PPCODE:\n";
+ pr " %s = guestfs_%s " n name;
+ generate_call_args ~handle:"g" (snd style);
+ pr ";\n";
+ do_cleanups ();
+ pr " if (%s == NULL)\n" n;
+ pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
+ pr " EXTEND (SP, %s->len);\n" n;
+ pr " for (i = 0; i < %s->len; ++i) {\n" n;
+ pr " hv = newHV ();\n";
+ List.iter (
+ function
+ | name, `String ->
+ pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
+ name (String.length name) n name
+ | name, `Int ->
+ pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
+ name (String.length name) n name
+ | name, `Char ->
+ pr " (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
+ name (String.length name) n name
+ ) cols;
+ pr " PUSHs (newRV (sv_2mortal ((SV *) hv)));\n";
+ pr " }\n";
+ pr " guestfs_free_%s_list (%s);\n" typ n
+
(* Generate Sys/Guestfs.pm. *)
and generate_perl_pm () =
generate_header HashStyle LGPLv2;
| RStringList n
| RPVList n
| RVGList n
- | RLVList n -> pr "@%s = " n
+ | RLVList n
+ | RDirentList n -> pr "@%s = " n
| RStat n
| RStatVFS n
| RHashtable n -> pr "%%%s = " n
pr "\n";
) ["stat", stat_cols; "statvfs", statvfs_cols];
+ (* Dirent structures, turned into Python dictionaries. *)
+ pr "static PyObject *\n";
+ pr "put_dirent (struct guestfs_dirent *dirent)\n";
+ pr "{\n";
+ pr " PyObject *dict;\n";
+ pr "\n";
+ pr " dict = PyDict_New ();\n";
+ List.iter (
+ function
+ | name, `Int ->
+ pr " PyDict_SetItemString (dict, \"%s\",\n" name;
+ pr " PyLong_FromLongLong (dirent->%s));\n" name
+ | name, `Char ->
+ pr " PyDict_SetItemString (dict, \"%s\",\n" name;
+ pr " PyString_FromStringAndSize (&dirent->%s, 1));\n" name
+ | name, `String ->
+ pr " PyDict_SetItemString (dict, \"%s\",\n" name;
+ pr " PyString_FromString (dirent->%s));\n" name
+ ) dirent_cols;
+ pr " return dict;\n";
+ pr "};\n";
+ pr "\n";
+
+ pr "static PyObject *\n";
+ pr "put_dirent_list (struct guestfs_dirent_list *dirents)\n";
+ pr "{\n";
+ pr " PyObject *list;\n";
+ pr " int i;\n";
+ pr "\n";
+ pr " list = PyList_New (dirents->len);\n";
+ pr " for (i = 0; i < dirents->len; ++i)\n";
+ pr " PyList_SetItem (list, i, put_dirent (&dirents->val[i]));\n";
+ pr " return list;\n";
+ pr "};\n";
+ pr "\n";
+
(* Python wrapper functions. *)
List.iter (
fun (name, style, _, _, _, _, _) ->
| RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
| RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
| RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
- | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
+ | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL"
+ | RDirentList n -> pr " struct guestfs_dirent_list *r;\n"; "NULL" in
List.iter (
function
| RHashtable n ->
pr " py_r = put_table (r);\n";
pr " free_strings (r);\n"
+ | RDirentList n ->
+ pr " py_r = put_dirent_list (r);\n";
+ pr " guestfs_free_dirent_list (r);\n"
);
pr " return py_r;\n";
| RStatVFS _ ->
doc ^ "\n\nThis function returns a dictionary, with keys matching the various fields in the statvfs structure."
| RHashtable _ ->
- doc ^ "\n\nThis function returns a dictionary." in
+ doc ^ "\n\nThis function returns a dictionary."
+ | RDirentList _ ->
+ doc ^ "\n\nThis function returns a list of directory entries. Each directory entry is represented as a dictionary." in
let doc =
if List.mem ProtocolLimitWarning flags then
doc ^ "\n\n" ^ protocol_limit_warning
| RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
| RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
| RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
- | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
+ | RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL"
+ | RDirentList n -> pr " struct guestfs_dirent_list *r;\n"; "NULL" in
pr "\n";
pr " r = guestfs_%s " name;
pr " }\n";
pr " free (r);\n";
pr " return rv;\n"
+ | RDirentList n ->
+ generate_ruby_dirent_code "dirent" dirent_cols
);
pr "}\n";
pr " guestfs_free_lvm_%s_list (r);\n" typ;
pr " return rv;\n"
+(* Ruby code to return a dirent struct list. *)
+and generate_ruby_dirent_code typ cols =
+ pr " VALUE rv = rb_ary_new2 (r->len);\n";
+ pr " int i;\n";
+ pr " for (i = 0; i < r->len; ++i) {\n";
+ pr " VALUE hv = rb_hash_new ();\n";
+ List.iter (
+ function
+ | name, `String ->
+ pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
+ | name, (`Char|`Int) ->
+ pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
+ ) cols;
+ pr " rb_ary_push (rv, hv);\n";
+ pr " }\n";
+ pr " guestfs_free_%s_list (r);\n" typ;
+ pr " return rv;\n"
+
(* Generate Java bindings GuestFS.java file. *)
and generate_java_java () =
generate_header CStyle LGPLv2;
import com.redhat.et.libguestfs.Stat;
import com.redhat.et.libguestfs.StatVFS;
import com.redhat.et.libguestfs.IntBool;
+import com.redhat.et.libguestfs.Dirent;
/**
* The GuestFS object is a libguestfs handle.
| RStat _ -> pr "Stat ";
| RStatVFS _ -> pr "StatVFS ";
| RHashtable _ -> pr "HashMap<String,String> ";
+ | RDirentList _ -> pr "Dirent[] ";
);
if native then pr "_%s " name else pr "%s " name;
| name, `UUID -> pr " public String %s;\n" name
| name, `Bytes
| name, `Int -> pr " public long %s;\n" name
+ | name, `Char -> pr " public char %s;\n" name
| name, `OptPercent ->
pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
pr " public float %s;\n" name
| RConstString _ | RString _ -> pr "jstring ";
| RIntBool _ | RStat _ | RStatVFS _ | RHashtable _ ->
pr "jobject ";
- | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
+ | RStringList _ | RPVList _ | RVGList _ | RLVList _ | RDirentList _ ->
pr "jobjectArray ";
);
pr "JNICALL\n";
pr " jfieldID fl;\n";
pr " jobject jfl;\n";
pr " struct guestfs_lvm_lv_list *r;\n"; "NULL", "NULL"
- | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL" in
+ | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL"
+ | RDirentList _ ->
+ pr " jobjectArray jr;\n";
+ pr " jclass cl;\n";
+ pr " jfieldID fl;\n";
+ pr " jobject jfl;\n";
+ pr " struct guestfs_dirent_list *r;\n"; "NULL", "NULL" in
List.iter (
function
| String n
let needs_i =
(match fst style with
- | RStringList _ | RPVList _ | RVGList _ | RLVList _ -> true
+ | RStringList _ | RPVList _ | RVGList _ | RLVList _
+ | RDirentList _ -> true
| RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
| RString _ | RIntBool _ | RStat _ | RStatVFS _
| RHashtable _ -> false) ||
(* XXX *)
pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
pr " return NULL;\n"
+ | RDirentList _ ->
+ generate_java_dirent_return "dirent" "Dirent" dirent_cols
);
pr "}\n";
pr " guestfs_free_lvm_%s_list (r);\n" typ;
pr " return jr;\n"
+and generate_java_dirent_return typ jtyp cols =
+ pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
+ pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
+ pr " for (i = 0; i < r->len; ++i) {\n";
+ pr " jfl = (*env)->AllocObject (env, cl);\n";
+ List.iter (
+ function
+ | name, `String ->
+ pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
+ pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
+ | name, (`Char|`Int) ->
+ pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
+ pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
+ ) cols;
+ pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
+ pr " }\n";
+ pr " guestfs_free_%s_list (r);\n" typ;
+ pr " return jr;\n"
+
and generate_haskell_hs () =
generate_header HaskellStyle LGPLv2;
| RLVList _, _
| RStat _, _
| RStatVFS _, _
- | RHashtable _, _ -> false in
+ | RHashtable _, _
+ | RDirentList _, _ -> false in
pr "\
{-# INCLUDE <guestfs.h> #-}
pr " fail err\n";
| RConstString _ | RString _ | RStringList _ | RIntBool _
| RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
- | RHashtable _ ->
+ | RHashtable _ | RDirentList _ ->
pr " if (r == nullPtr)\n";
pr " then do\n";
pr " err <- last_error h\n";
| RLVList _
| RStat _
| RStatVFS _
- | RHashtable _ ->
+ | RHashtable _
+ | RDirentList _ ->
pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
);
pr "\n";
| RStat _ -> pr "Stat"
| RStatVFS _ -> pr "StatVFS"
| RHashtable _ -> pr "Hashtable"
+ | RDirentList _ -> pr "[Dirent]"
);
pr ")"
pr " }\n";
pr " strs[n*2] = NULL;\n";
pr " return strs;\n"
+ | RDirentList _ ->
+ pr " struct guestfs_dirent_list *r;\n";
+ pr " int i;\n";
+ pr " r = malloc (sizeof (struct guestfs_dirent_list));\n";
+ pr " sscanf (val, \"%%d\", &r->len);\n";
+ pr " r->val = calloc (r->len, sizeof (struct guestfs_dirent));\n";
+ pr " for (i = 0; i < r->len; ++i)\n";
+ pr " r->val[i].ino = i;\n";
+ pr " return r;\n"
);
pr "}\n";
pr "\n"
| RConstString _
| RString _ | RStringList _ | RIntBool _
| RPVList _ | RVGList _ | RLVList _ | RStat _ | RStatVFS _
- | RHashtable _ ->
+ | RHashtable _
+ | RDirentList _ ->
pr " return NULL;\n"
);
pr "}\n";
generate_java_struct "StatVFS" statvfs_cols;
close ();
+ let close = output_to "java/com/redhat/et/libguestfs/Dirent.java" in
+ generate_java_struct "Dirent" dirent_cols;
+ close ();
+
let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
generate_java_c ();
close ();
return ctx.ret.oldmask;
}
+struct readdir_ctx {
+ /* This flag is set by the callbacks, so we know we've done
+ * the callbacks as expected, and in the right sequence.
+ * 0 = not called, 1 = reply_cb called.
+ */
+ int cb_sequence;
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_readdir_ret ret;
+};
+
+static void readdir_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct readdir_ctx *ctx = (struct readdir_ctx *) data;
+
+ /* This should definitely not happen. */
+ if (ctx->cb_sequence != 0) {
+ ctx->cb_sequence = 9999;
+ error (g, "%s: internal error: reply callback called twice", "guestfs_readdir");
+ return;
+ }
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_readdir");
+ return;
+ }
+ if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+ error (g, "%s: failed to parse reply error", "guestfs_readdir");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_readdir_ret (xdr, &ctx->ret)) {
+ error (g, "%s: failed to parse reply", "guestfs_readdir");
+ return;
+ }
+ done:
+ ctx->cb_sequence = 1;
+}
+
+struct guestfs_dirent_list *guestfs_readdir (guestfs_h *g,
+ const char *dir)
+{
+ struct guestfs_readdir_args args;
+ struct readdir_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_readdir") == -1) return NULL;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.dir = (char *) dir;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_READDIR,
+ (xdrproc_t) xdr_guestfs_readdir_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, readdir_reply_cb, &ctx);
+ (void) ml->main_loop_run (ml, g);
+ guestfs_set_reply_callback (g, NULL, NULL);
+ if (ctx.cb_sequence != 1) {
+ error (g, "%s reply failed, see earlier error messages", "guestfs_readdir");
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_READDIR, serial) == -1) {
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ free (ctx.err.error_message);
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ guestfs_end_busy (g);
+ /* caller will free this */
+ return safe_memdup (g, &ctx.ret.entries, sizeof (ctx.ret.entries));
+}
+
extern int guestfs_mknod_b (guestfs_h *handle, int mode, int devmajor, int devminor, const char *path);
extern int guestfs_mknod_c (guestfs_h *handle, int mode, int devmajor, int devminor, const char *path);
extern int guestfs_umask (guestfs_h *handle, int mask);
+extern struct guestfs_dirent_list *guestfs_readdir (guestfs_h *handle, const char *dir);
int64_t namemax;
};
+struct guestfs_dirent {
+ int64_t ino;
+ char ftyp;
+ char *name;
+};
+
+struct guestfs_dirent_list {
+ uint32_t len;
+ struct guestfs_dirent *val;
+};
+
free (x);
}
+void
+guestfs_free_dirent_list (struct guestfs_dirent_list *x)
+{
+ xdr_free ((xdrproc_t) xdr_guestfs_int_dirent_list, (char *) x);
+ free (x);
+}
+
/* We don't know if stdout_event or sock_read_event will be the
* first to receive EOF if the qemu process dies. This function
* has the common cleanup code for both.
extern void guestfs_free_lvm_pv_list (struct guestfs_lvm_pv_list *);
extern void guestfs_free_lvm_vg_list (struct guestfs_lvm_vg_list *);
extern void guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *);
+extern void guestfs_free_dirent_list (struct guestfs_dirent_list *);
/* Low-level event API. */
typedef void (*guestfs_send_cb) (guestfs_h *g, void *data);
}
bool_t
+xdr_guestfs_int_dirent (XDR *xdrs, guestfs_int_dirent *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_quad_t (xdrs, &objp->ino))
+ return FALSE;
+ if (!xdr_char (xdrs, &objp->ftyp))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->name, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_int_dirent_list (XDR *xdrs, guestfs_int_dirent_list *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->guestfs_int_dirent_list_val, (u_int *) &objp->guestfs_int_dirent_list_len, ~0,
+ sizeof (guestfs_int_dirent), (xdrproc_t) xdr_guestfs_int_dirent))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_mount_args (XDR *xdrs, guestfs_mount_args *objp)
{
register int32_t *buf;
}
bool_t
+xdr_guestfs_readdir_args (XDR *xdrs, guestfs_readdir_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->dir, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_readdir_ret (XDR *xdrs, guestfs_readdir_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_guestfs_int_dirent_list (xdrs, &objp->entries))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
{
register int32_t *buf;
};
typedef struct guestfs_int_statvfs guestfs_int_statvfs;
+struct guestfs_int_dirent {
+ quad_t ino;
+ char ftyp;
+ char *name;
+};
+typedef struct guestfs_int_dirent guestfs_int_dirent;
+
+typedef struct {
+ u_int guestfs_int_dirent_list_len;
+ guestfs_int_dirent *guestfs_int_dirent_list_val;
+} guestfs_int_dirent_list;
+
struct guestfs_mount_args {
char *device;
char *mountpoint;
};
typedef struct guestfs_umask_ret guestfs_umask_ret;
+struct guestfs_readdir_args {
+ char *dir;
+};
+typedef struct guestfs_readdir_args guestfs_readdir_args;
+
+struct guestfs_readdir_ret {
+ guestfs_int_dirent_list entries;
+};
+typedef struct guestfs_readdir_ret guestfs_readdir_ret;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
GUESTFS_PROC_MKNOD_B = 135,
GUESTFS_PROC_MKNOD_C = 136,
GUESTFS_PROC_UMASK = 137,
- GUESTFS_PROC_NR_PROCS = 137 + 1,
+ GUESTFS_PROC_READDIR = 138,
+ GUESTFS_PROC_NR_PROCS = 138 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
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_int_dirent (XDR *, guestfs_int_dirent*);
+extern bool_t xdr_guestfs_int_dirent_list (XDR *, guestfs_int_dirent_list*);
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*);
extern bool_t xdr_guestfs_mknod_c_args (XDR *, guestfs_mknod_c_args*);
extern bool_t xdr_guestfs_umask_args (XDR *, guestfs_umask_args*);
extern bool_t xdr_guestfs_umask_ret (XDR *, guestfs_umask_ret*);
+extern bool_t xdr_guestfs_readdir_args (XDR *, guestfs_readdir_args*);
+extern bool_t xdr_guestfs_readdir_ret (XDR *, guestfs_readdir_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*);
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_int_dirent ();
+extern bool_t xdr_guestfs_int_dirent_list ();
extern bool_t xdr_guestfs_mount_args ();
extern bool_t xdr_guestfs_touch_args ();
extern bool_t xdr_guestfs_cat_args ();
extern bool_t xdr_guestfs_mknod_c_args ();
extern bool_t xdr_guestfs_umask_args ();
extern bool_t xdr_guestfs_umask_ret ();
+extern bool_t xdr_guestfs_readdir_args ();
+extern bool_t xdr_guestfs_readdir_ret ();
extern bool_t xdr_guestfs_procedure ();
extern bool_t xdr_guestfs_message_direction ();
extern bool_t xdr_guestfs_message_status ();
hyper namemax;
};
+struct guestfs_int_dirent {
+ hyper ino;
+ char ftyp;
+ string name<>;
+};
+
+typedef struct guestfs_int_dirent guestfs_int_dirent_list<>;
+
struct guestfs_mount_args {
string device<>;
string mountpoint<>;
int oldmask;
};
+struct guestfs_readdir_args {
+ string dir<>;
+};
+
+struct guestfs_readdir_ret {
+ guestfs_int_dirent_list entries;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
GUESTFS_PROC_MKNOD_B = 135,
GUESTFS_PROC_MKNOD_C = 136,
GUESTFS_PROC_UMASK = 137,
+ GUESTFS_PROC_READDIR = 138,
GUESTFS_PROC_NR_PROCS
};