gboolean mcview_load_command_output (mcview_t * view, const char *command) { FILE *fp; mcview_close_datasource (view); open_error_pipe (); fp = popen (command, "r"); if (fp == NULL) { /* Avoid two messages. Message from stderr has priority. */ mcview_display (view); if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL)) mcview_show_error (view, _("Cannot spawn child process")); return FALSE; } /* First, check if filter produced any output */ mcview_set_datasource_stdio_pipe (view, fp); if (!mcview_get_byte (view, 0, NULL)) { mcview_close_datasource (view); /* Avoid two messages. Message from stderr has priority. */ mcview_display (view); if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL)) mcview_show_error (view, _("Empty output from child filter")); return FALSE; } else { /* * At least something was read correctly. Close stderr and let * program die if it will try to write something there. * * Ideally stderr should be read asynchronously to prevent programs * from blocking (poll/select multiplexor). */ close_error_pipe (D_NORMAL, NULL); } return TRUE; }
void mcview_close_datasource (mcview_t * view) { switch (view->datasource) { case DS_NONE: break; case DS_STDIO_PIPE: if (view->ds_stdio_pipe != NULL) { (void) pclose (view->ds_stdio_pipe); mcview_display (view); close_error_pipe (D_NORMAL, NULL); view->ds_stdio_pipe = NULL; } mcview_growbuf_free (view); break; case DS_VFS_PIPE: if (view->ds_vfs_pipe != -1) { (void) mc_close (view->ds_vfs_pipe); view->ds_vfs_pipe = -1; } mcview_growbuf_free (view); break; case DS_FILE: (void) mc_close (view->ds_file_fd); view->ds_file_fd = -1; MC_PTR_FREE (view->ds_file_data); break; case DS_STRING: MC_PTR_FREE (view->ds_string_data); break; default: #ifdef HAVE_ASSERT_H assert (!"Unknown datasource type") #endif ; } view->datasource = DS_NONE; }
/* * Main loop for reading an archive. * Return 0 on success, -1 on error. */ static int extfs_read_archive (int fstype, const char *name, struct archive **pparc) { FILE *extfsd; char *buffer; struct archive *current_archive; char *current_file_name, *current_link_name; if ((extfsd = extfs_open_archive (fstype, name, ¤t_archive)) == NULL) { message (1, MSG_ERROR, _("Cannot open %s archive\n%s"), extfs_prefixes[fstype], name); return -1; } buffer = g_malloc (4096); while (fgets (buffer, 4096, extfsd) != NULL) { struct stat hstat; current_link_name = NULL; if (vfs_parse_ls_lga (buffer, &hstat, ¤t_file_name, ¤t_link_name)) { struct entry *entry, *pent; struct inode *inode; char *p, *q, *cfn = current_file_name; if (*cfn) { if (*cfn == '/') cfn++; p = strchr (cfn, 0); if (p != cfn && *(p - 1) == '/') *(p - 1) = 0; p = strrchr (cfn, '/'); if (p == NULL) { p = cfn; q = strchr (cfn, 0); } else { *(p++) = 0; q = cfn; } if (S_ISDIR (hstat.st_mode) && (!strcmp (p, ".") || !strcmp (p, ".."))) goto read_extfs_continue; pent = extfs_find_entry (current_archive->root_entry, q, 1, 0); if (pent == NULL) { /* FIXME: Should clean everything one day */ g_free (buffer); pclose (extfsd); close_error_pipe (1, _("Inconsistent extfs archive")); return -1; } entry = g_new (struct entry, 1); entry->name = g_strdup (p); entry->next_in_dir = NULL; entry->dir = pent; if (pent->inode->last_in_subdir) { pent->inode->last_in_subdir->next_in_dir = entry; pent->inode->last_in_subdir = entry; } if (!S_ISLNK (hstat.st_mode) && current_link_name != NULL) { pent = extfs_find_entry (current_archive->root_entry, current_link_name, 0, 0); if (pent == NULL) { /* FIXME: Should clean everything one day */ g_free (buffer); pclose (extfsd); close_error_pipe (1, _("Inconsistent extfs archive")); return -1; } else { entry->inode = pent->inode; pent->inode->nlink++; } } else { inode = g_new (struct inode, 1); entry->inode = inode; inode->local_filename = NULL; inode->inode = (current_archive->inode_counter)++; inode->nlink = 1; inode->dev = current_archive->rdev; inode->archive = current_archive; inode->mode = hstat.st_mode; #ifdef HAVE_STRUCT_STAT_ST_RDEV inode->rdev = hstat.st_rdev; #else inode->rdev = 0; #endif inode->uid = hstat.st_uid; inode->gid = hstat.st_gid; inode->size = hstat.st_size; inode->mtime = hstat.st_mtime; inode->atime = hstat.st_atime; inode->ctime = hstat.st_ctime; inode->first_in_subdir = NULL; inode->last_in_subdir = NULL; if (current_link_name != NULL && S_ISLNK (hstat.st_mode)) { inode->linkname = current_link_name; current_link_name = NULL; } else { if (S_ISLNK (hstat.st_mode)) inode->mode &= ~S_IFLNK; /* You *DON'T* want to do this always */ inode->linkname = NULL; } if (S_ISDIR (hstat.st_mode)) extfs_make_dots (entry); } } read_extfs_continue: g_free (current_file_name); g_free (current_link_name); } } g_free (buffer); /* Check if extfs 'list' returned 0 */ if (pclose (extfsd) != 0) { extfs_free (current_archive); close_error_pipe (1, _("Inconsistent extfs archive")); return -1; } close_error_pipe (1, NULL); *pparc = current_archive; return 0; }
static FILE * extfs_open_archive (int fstype, const char *name, struct archive **pparc) { static dev_t archive_counter = 0; FILE *result; mode_t mode; char *cmd; char *mc_extfsdir; struct stat mystat; struct archive *current_archive; struct entry *root_entry; char *local_name = NULL, *tmp = 0; int uses_archive = extfs_need_archive[fstype]; if (uses_archive) { if (mc_stat (name, &mystat) == -1) return NULL; if (!vfs_file_is_local (name)) { local_name = mc_getlocalcopy (name); if (local_name == NULL) return NULL; } tmp = name_quote (name, 0); } mc_extfsdir = concat_dir_and_file (mc_home, "extfs" PATH_SEP_STR); cmd = g_strconcat (mc_extfsdir, extfs_prefixes[fstype], " list ", local_name ? local_name : tmp, (char *) NULL); g_free (tmp); g_free (mc_extfsdir); open_error_pipe (); result = popen (cmd, "r"); g_free (cmd); if (result == NULL) { close_error_pipe (1, NULL); if (local_name) { mc_ungetlocalcopy (name, local_name, 0); g_free(local_name); } return NULL; } #ifdef ___QNXNTO__ setvbuf (result, NULL, _IONBF, 0); #endif current_archive = g_new (struct archive, 1); current_archive->fstype = fstype; current_archive->name = name ? g_strdup (name) : NULL; current_archive->local_name = local_name; if (local_name != NULL) mc_stat (local_name, ¤t_archive->local_stat); current_archive->inode_counter = 0; current_archive->fd_usage = 0; current_archive->rdev = archive_counter++; current_archive->next = first_archive; first_archive = current_archive; mode = mystat.st_mode & 07777; if (mode & 0400) mode |= 0100; if (mode & 0040) mode |= 0010; if (mode & 0004) mode |= 0001; mode |= S_IFDIR; root_entry = extfs_generate_entry (current_archive, "/", NULL, mode); root_entry->inode->uid = mystat.st_uid; root_entry->inode->gid = mystat.st_gid; root_entry->inode->atime = mystat.st_atime; root_entry->inode->ctime = mystat.st_ctime; root_entry->inode->mtime = mystat.st_mtime; current_archive->root_entry = root_entry; *pparc = current_archive; return result; }
void mcview_growbuf_read_until (mcview_t * view, off_t ofs) { ssize_t nread; byte *p; size_t bytesfree; gboolean short_read; assert (view->growbuf_in_use); if (view->growbuf_finished) return; short_read = FALSE; while (mcview_growbuf_filesize (view) < ofs || short_read) { if (view->growbuf_lastindex == VIEW_PAGE_SIZE) { /* Append a new block to the growing buffer */ byte *newblock = g_try_malloc (VIEW_PAGE_SIZE); if (newblock == NULL) return; g_ptr_array_add (view->growbuf_blockptr, newblock); view->growbuf_lastindex = 0; } p = g_ptr_array_index (view->growbuf_blockptr, view->growbuf_blockptr->len - 1) + view->growbuf_lastindex; bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex; if (view->datasource == DS_STDIO_PIPE) { nread = fread (p, 1, bytesfree, view->ds_stdio_pipe); if (nread == 0) { view->growbuf_finished = TRUE; (void) pclose (view->ds_stdio_pipe); mcview_display (view); close_error_pipe (D_NORMAL, NULL); view->ds_stdio_pipe = NULL; return; } } else { assert (view->datasource == DS_VFS_PIPE); do { nread = mc_read (view->ds_vfs_pipe, p, bytesfree); } while (nread == -1 && errno == EINTR); if (nread == -1 || nread == 0) { view->growbuf_finished = TRUE; (void) mc_close (view->ds_vfs_pipe); view->ds_vfs_pipe = -1; return; } } short_read = ((size_t) nread < bytesfree); view->growbuf_lastindex += nread; } }
static int sfs_vfmake (struct vfs_class *me, const char *name, char *cache) { char *inpath, *op; int w; char pad[10240]; char *s, *t = pad; int was_percent = 0; char *pname; /* name of parent archive */ char *pqname; /* name of parent archive, quoted */ pname = g_strdup (name); vfs_split (pname, &inpath, &op); if ((w = (*me->which) (me, op)) == -1) vfs_die ("This cannot happen... Hopefully.\n"); if (!(sfs_flags[w] & F_1) && strcmp (pname, "/")) { g_free (pname); return -1; } /* if ((sfs_flags[w] & F_2) || (!inpath) || (!*inpath)); else return -1; */ if (!(sfs_flags[w] & F_NOLOCALCOPY)) { s = mc_getlocalcopy (pname); if (!s) { g_free (pname); return -1; } pqname = name_quote (s, 0); g_free (s); } else { pqname = name_quote (pname, 0); } g_free (pname); #define COPY_CHAR \ if ((size_t) (t-pad) > sizeof(pad)) { \ g_free (pqname); \ return -1; \ } \ else \ *t++ = *s; #define COPY_STRING(a) \ if ((t-pad)+strlen(a)>sizeof(pad)) { \ g_free (pqname); \ return -1; \ } else { \ strcpy (t, a); \ t+= strlen(a); \ } for (s = sfs_command[w]; *s; s++) { if (was_percent) { const char *ptr = NULL; was_percent = 0; switch (*s) { case '1': ptr = pqname; break; case '2': ptr = op + strlen (sfs_prefix[w]); break; case '3': ptr = cache; break; case '%': COPY_CHAR; continue; } COPY_STRING (ptr); } else { if (*s == '%') was_percent = 1; else COPY_CHAR; } } g_free (pqname); open_error_pipe (); if (my_system (EXECUTE_AS_SHELL, "/bin/sh", pad)) { close_error_pipe (1, NULL); return -1; } close_error_pipe (0, NULL); return 0; /* OK */ }