struct guestfs_stat_list * guestfs__lstatlist (guestfs_h *g, const char *dir, char * const*names) { size_t len = guestfs___count_strings (names); size_t old_len; struct guestfs_stat_list *ret; ret = safe_malloc (g, sizeof *ret); ret->len = 0; ret->val = NULL; while (len > 0) { CLEANUP_FREE_STAT_LIST struct guestfs_stat_list *stats = NULL; /* Note we don't need to free up the strings because take_strings * does not do a deep copy. */ CLEANUP_FREE char **first = take_strings (g, names, LSTATLIST_MAX, &names); len = len <= LSTATLIST_MAX ? 0 : len - LSTATLIST_MAX; stats = guestfs_internal_lstatlist (g, dir, first); if (stats == NULL) { guestfs_free_stat_list (ret); return NULL; } /* Append stats to ret. */ old_len = ret->len; ret->len += stats->len; ret->val = safe_realloc (g, ret->val, ret->len * sizeof (struct guestfs_stat)); memcpy (&ret->val[old_len], stats->val, stats->len * sizeof (struct guestfs_stat)); } return ret; }
static int mount_local_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { DECL_G (); DEBUG_CALL ("%s, %p, %ld", path, buf, (long) offset); time_t now; time (&now); dir_cache_remove_all_expired (g, now); struct guestfs_dirent_list *ents; ents = guestfs_readdir (g, path); if (ents == NULL) RETURN_ERRNO; size_t i; for (i = 0; i < ents->len; ++i) { struct stat stat; memset (&stat, 0, sizeof stat); stat.st_ino = ents->val[i].ino; switch (ents->val[i].ftyp) { case 'b': stat.st_mode = S_IFBLK; break; case 'c': stat.st_mode = S_IFCHR; break; case 'd': stat.st_mode = S_IFDIR; break; case 'f': stat.st_mode = S_IFIFO; break; case 'l': stat.st_mode = S_IFLNK; break; case 'r': stat.st_mode = S_IFREG; break; case 's': stat.st_mode = S_IFSOCK; break; case 'u': case '?': default: stat.st_mode = 0; } /* Copied from the example, which also ignores 'offset'. I'm * not quite sure how this is ever supposed to work on large * directories. XXX */ if (filler (buf, ents->val[i].name, &stat, 0)) break; } /* Now prepopulate the directory caches. This step is just an * optimization, don't worry if it fails. */ char **names = malloc ((ents->len + 1) * sizeof (char *)); if (names) { for (i = 0; i < ents->len; ++i) names[i] = ents->val[i].name; names[i] = NULL; struct guestfs_stat_list *ss = guestfs_lstatlist (g, path, names); if (ss) { for (i = 0; i < ss->len; ++i) { if (ss->val[i].ino >= 0) { struct stat statbuf; statbuf.st_dev = ss->val[i].dev; statbuf.st_ino = ss->val[i].ino; statbuf.st_mode = ss->val[i].mode; statbuf.st_nlink = ss->val[i].nlink; statbuf.st_uid = ss->val[i].uid; statbuf.st_gid = ss->val[i].gid; statbuf.st_rdev = ss->val[i].rdev; statbuf.st_size = ss->val[i].size; statbuf.st_blksize = ss->val[i].blksize; statbuf.st_blocks = ss->val[i].blocks; statbuf.st_atime = ss->val[i].atime; statbuf.st_mtime = ss->val[i].mtime; statbuf.st_ctime = ss->val[i].ctime; lsc_insert (g, path, names[i], now, &statbuf); } } guestfs_free_stat_list (ss); } struct guestfs_xattr_list *xattrs = guestfs_lxattrlist (g, path, names); if (xattrs) { size_t ni, num; struct guestfs_xattr *first; struct guestfs_xattr_list *copy; for (i = 0, ni = 0; i < xattrs->len; ++i, ++ni) { /* assert (strlen (xattrs->val[i].attrname) == 0); */ if (xattrs->val[i].attrval_len > 0) { ++i; first = &xattrs->val[i]; num = 0; for (; i < xattrs->len && strlen (xattrs->val[i].attrname) > 0; ++i) num++; copy = copy_xattr_list (first, num); if (copy) xac_insert (g, path, names[ni], now, copy); i--; } } guestfs_free_xattr_list (xattrs); } char **links = guestfs_readlinklist (g, path, names); if (links) { for (i = 0; names[i] != NULL; ++i) { if (links[i][0]) /* Note that rlc_insert owns the string links[i] after this, */ rlc_insert (g, path, names[i], now, links[i]); else /* which is why we have to free links[i] here. */ free (links[i]); } free (links); /* free the array, not the strings */ } free (names); } guestfs_free_dirent_list (ents); return 0; }