struct guestfs_stat_list * guestfs_impl_lstatlist (guestfs_h *g, const char *dir, char * const*names) { CLEANUP_FREE_STATNS_LIST struct guestfs_statns_list *r; struct guestfs_stat_list *ret; size_t i; r = guestfs_lstatnslist (g, dir, names); if (r == NULL) return NULL; ret = safe_malloc (g, sizeof *ret); ret->len = r->len; ret->val = safe_calloc (g, r->len, sizeof (struct guestfs_stat)); for (i = 0; i < r->len; ++i) statns_to_old_stat (&r->val[i], &ret->val[i]); return ret; }
static int mount_local_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { time_t now; size_t i; char **names; CLEANUP_FREE_DIRENT_LIST struct guestfs_dirent_list *ents = NULL; DECL_G (); DEBUG_CALL ("%s, %p, %ld", path, buf, (long) offset); time (&now); dir_cache_remove_all_expired (g, now); ents = guestfs_readdir (g, path); if (ents == NULL) RETURN_ERRNO; 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. */ names = malloc ((ents->len + 1) * sizeof (char *)); if (names) { CLEANUP_FREE_STATNS_LIST struct guestfs_statns_list *ss = NULL; CLEANUP_FREE_XATTR_LIST struct guestfs_xattr_list *xattrs = NULL; char **links; for (i = 0; i < ents->len; ++i) names[i] = ents->val[i].name; names[i] = NULL; ss = guestfs_lstatnslist (g, path, names); if (ss) { for (i = 0; i < ss->len; ++i) { if (ss->val[i].st_ino >= 0) { struct stat statbuf; memset (&statbuf, 0, sizeof statbuf); statbuf.st_dev = ss->val[i].st_dev; statbuf.st_ino = ss->val[i].st_ino; statbuf.st_mode = ss->val[i].st_mode; statbuf.st_nlink = ss->val[i].st_nlink; statbuf.st_uid = ss->val[i].st_uid; statbuf.st_gid = ss->val[i].st_gid; statbuf.st_rdev = ss->val[i].st_rdev; statbuf.st_size = ss->val[i].st_size; statbuf.st_blksize = ss->val[i].st_blksize; statbuf.st_blocks = ss->val[i].st_blocks; statbuf.st_atime = ss->val[i].st_atime_sec; #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC statbuf.st_atim.tv_nsec = ss->val[i].st_atime_nsec; #endif statbuf.st_mtime = ss->val[i].st_mtime_sec; #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC statbuf.st_mtim.tv_nsec = ss->val[i].st_mtime_nsec; #endif statbuf.st_ctime = ss->val[i].st_ctime_sec; #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC statbuf.st_ctim.tv_nsec = ss->val[i].st_ctime_nsec; #endif lsc_insert (g, path, names[i], now, &statbuf); } } } 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 (g, first, num); if (copy) xac_insert (g, path, names[ni], now, copy); i--; } } } 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); } return 0; }