示例#1
0
文件: direntry.c 项目: dborca/mc
/*
 * Dissect the path and create corresponding superblock.  Note that inname
 * can be changed and the result may point inside the original string.
 */
const char *
vfs_s_get_path_mangle (struct vfs_class *me, char *inname,
		       struct vfs_s_super **archive, int flags)
{
    const char *retval;
    char *local, *op;
    const char *archive_name;
    int result = -1;
    struct vfs_s_super *super;
    void *cookie = NULL;

    archive_name = inname;
    vfs_split (inname, &local, &op);
    retval = (local) ? local : "";

    if (MEDATA->archive_check)
	if (!(cookie = MEDATA->archive_check (me, archive_name, op)))
	    return NULL;

    for (super = MEDATA->supers; super != NULL; super = super->next) {
	/* 0 == other, 1 == same, return it, 2 == other but stop scanning */
	int i;
	if ((i =
	     MEDATA->archive_same (me, super, archive_name, op, cookie))) {
	    if (i == 1)
		goto return_success;
	    else
		break;
	}
    }

    if (flags & FL_NO_OPEN)
	ERRNOR (EIO, NULL);

    super = vfs_s_new_super (me);
    result = MEDATA->open_archive (me, super, archive_name, op);
    if (result == -1) {
	vfs_s_free_super (me, super);
	ERRNOR (EIO, NULL);
    }
    if (!super->name)
	vfs_die ("You have to fill name\n");
    if (!super->root)
	vfs_die ("You have to fill root inode\n");

    vfs_s_insert_super (me, super);
    vfs_stamp_create (me, super);

  return_success:
    *archive = super;
    return retval;
}
/* Returns fd of the open tar file */
static int tar_open_archive (vfs *me, char *name, vfs_s_super *archive)
{
    int result, type;
    long size;
    mode_t mode;
    struct vfs_s_inode *root;
    
    result = mc_open (name, O_RDONLY);
    if (result == -1) {
        message_2s (1, MSG_ERROR, _("Couldn't open tar archive\n%s"), name);
	ERRNOR (ENOENT, -1);
    }
    
    archive->name = strdup (name);
    mc_stat (name, &(archive->u.tar.tarstat));
    archive->u.tar.fd = -1;

    /* Find out the method to handle this tar file */
    size = is_gunzipable (result, &type);
    mc_lseek (result, 0, SEEK_SET);
    if (size > 0) {
	char *s;
	mc_close( result );
	s = copy_strings( archive->name, decompress_extension (type), NULL );
	result = mc_open (s, O_RDONLY);
	if (result == -1) 
	    message_2s (1, MSG_ERROR, _("Couldn't open tar archive\n%s"), s);
	free(s);
	if (result == -1)
	    ERRNOR (ENOENT, -1);
    }
   
    archive->u.tar.fd = result;
    mode = archive->u.tar.tarstat.st_mode & 07777;
    if (mode & 0400) mode |= 0100;
    if (mode & 0040) mode |= 0010;
    if (mode & 0004) mode |= 0001;
    mode |= S_IFDIR;

    root = vfs_s_new_inode (me, archive, &archive->u.tar.tarstat);
    root->st.st_mode = mode;
    root->u.tar.data_offset = -1;
    root->st.st_nlink++;
    root->st.st_dev = MEDATA->rdev++;

    vfs_s_add_dots (me, root, NULL);
    archive->root = root;

    return result;
}
示例#3
0
文件: direntry.c 项目: dborca/mc
char *
vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino)
{
    if (!ino->ent)
	ERRNOR (EAGAIN, NULL);

    if (!(MEDATA->flags & VFS_S_REMOTE)) {
	/* archives */
	char *newpath;
	char *path = g_strdup (ino->ent->name);
	while (1) {
	    ino = ino->ent->dir;
	    if (ino == ino->super->root)
		break;
	    newpath = g_strconcat (ino->ent->name, "/", path, (char *) NULL);
	    g_free (path);
	    path = newpath;
	}
	return path;
    }

    /* remote systems */
    if ((!ino->ent->dir) || (!ino->ent->dir->ent))
	return g_strdup (ino->ent->name);

    return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR,
			ino->ent->name, (char *) NULL);
}
static int tar_read (void *fh, char *buffer, int count)
{
    off_t begin = FH->ino->u.tar.data_offset;
    int fd = FH_SUPER->u.tar.fd;
    vfs *me = FH_SUPER->me;

    if (mc_lseek (fd, begin + FH->pos, SEEK_SET) != 
        begin + FH->pos) ERRNOR (EIO, -1);

    count = VFS_MIN(count, FH->ino->st.st_size - FH->pos);

    if ((count = mc_read (fd, buffer, count)) == -1) ERRNOR (errno, -1);

    FH->pos += count;
    return count;
}
示例#5
0
文件: fish.c 项目: dborca/mc
static int
fish_linear_read (struct vfs_class *me, struct vfs_s_fh *fh, void *buf, int len)
{
    struct vfs_s_super *super = FH_SUPER;
    int n = 0;
    len = MIN( fh->u.fish.total - fh->u.fish.got, len );
    disable_interrupt_key();
    while (len && ((n = read (SUP.sockr, buf, len))<0)) {
        if ((errno == EINTR) && !got_interrupt())
	    continue;
	break;
    }
    enable_interrupt_key();

    if (n>0) fh->u.fish.got += n;
    if (n<0) fish_linear_abort(me, fh);
    if ((!n) && ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE)))
        ERRNOR (E_REMOTE, -1);
    ERRNOR (errno, n);
}
示例#6
0
文件: fish.c 项目: dborca/mc
static int
fish_send_command(struct vfs_class *me, struct vfs_s_super *super, const char *cmd, int flags)
{
    int r;

    r = fish_command (me, super, WAIT_REPLY, "%s", cmd);
    vfs_stamp_create (&vfs_fish_ops, super);
    if (r != COMPLETE) ERRNOR (E_REMOTE, -1);
    if (flags & OPT_FLUSH)
	vfs_s_invalidate(me, super);
    return 0;
}
示例#7
0
文件: fish.c 项目: dborca/mc
static int
fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset)
{
    char *name;
    char *quoted_name;
    if (offset)
        ERRNOR (E_NOTSUPP, 0);
    name = vfs_s_fullpath (me, fh->ino);
    if (!name)
	return 0;
    quoted_name = name_quote (name, 0);
    g_free (name);
    name = quoted_name;
    fh->u.fish.append = 0;
    offset = fish_command (me, FH_SUPER, WANT_STRING,
		"#RETR /%s\n"
		"if dd if=/%s of=/dev/null bs=1 count=1 2>/dev/null; then\n"
		"ls -ln /%s 2>/dev/null | (\n"
		  "read p l u g s r\n"
		  "echo \"$s\"\n"
		")\n"
		"echo '### 100'\n"
		"cat /%s\n"
		"echo '### 200'\n"
		"else\n"
		"echo '### 500'\n"
		"fi\n",
		name, name, name, name );
    g_free (name);
    if (offset != PRELIM) ERRNOR (E_REMOTE, 0);
    fh->linear = LS_LINEAR_OPEN;
    fh->u.fish.got = 0;
#if SIZEOF_OFF_T > SIZEOF_INT
    if (sscanf( reply_str, "%llu", &fh->u.fish.total )!=1)
#else
    if (sscanf( reply_str, "%u", &fh->u.fish.total )!=1)
#endif
	ERRNOR (E_REMOTE, 0);
    return 1;
}
示例#8
0
文件: direntry.c 项目: dborca/mc
/* If the entry is a symlink, find the entry for its target */
static struct vfs_s_entry *
vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry,
		       int follow)
{
    char *linkname;
    char *fullname = NULL;
    struct vfs_s_entry *target;

    if (follow == LINK_NO_FOLLOW)
	return entry;
    if (follow == 0)
	ERRNOR (ELOOP, NULL);
    if (!entry)
	ERRNOR (ENOENT, NULL);
    if (!S_ISLNK (entry->ino->st.st_mode))
	return entry;

    linkname = entry->ino->linkname;
    if (linkname == NULL)
	ERRNOR (EFAULT, NULL);

    /* make full path from relative */
    if (*linkname != PATH_SEP) {
	char *fullpath = vfs_s_fullpath (me, entry->dir);
	if (fullpath) {
	    fullname = g_strconcat (fullpath, "/", linkname, NULL);
	    linkname = fullname;
	    g_free (fullpath);
	}
    }

    target =
	(MEDATA->find_entry) (me, entry->dir->super->root, linkname,
			      follow - 1, 0);
    g_free (fullname);
    return target;
}
示例#9
0
文件: extfs.c 项目: dborca/mc
/*
 * Dissect the path and create corresponding superblock.  Note that inname
 * can be changed and the result may point inside the original string.
 */
static char *
extfs_get_path_mangle (struct vfs_class *me, char *inname, struct archive **archive,
		       int do_not_open)
{
    char *local, *op;
    const char *archive_name;
    int result = -1;
    struct archive *parc;
    int fstype;

    archive_name = inname;
    vfs_split (inname, &local, &op);

    fstype = extfs_which (me, op);

    if (fstype == -1)
	return NULL;
    if (!local)
	local = inname + strlen (inname);

    /*
     * All filesystems should have some local archive, at least
     * it can be '/'.
     */
    for (parc = first_archive; parc != NULL; parc = parc->next)
	if (parc->name) {
	    if (!strcmp (parc->name, archive_name)) {
		vfs_stamp (&vfs_extfs_ops, (vfsid) parc);
		goto return_success;
	    }
	}

    result =
	do_not_open ? -1 : extfs_read_archive (fstype, archive_name,
					       &parc);
    if (result == -1)
	ERRNOR (EIO, NULL);

  return_success:
    *archive = parc;
    return local;
}
示例#10
0
文件: fish.c 项目: dborca/mc
static int
fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *localname)
{
    struct vfs_s_super *super = FH_SUPER;
    int n, total;
    char buffer[8192];
    struct stat s;
    int was_error = 0;
    int h;
    char *quoted_name;

    h = open (localname, O_RDONLY);

    if (h == -1)
	ERRNOR (EIO, -1);
    if (fstat(h, &s)<0) {
	close (h);
	ERRNOR (EIO, -1);
    }

    /* First, try this as stor:
     *
     *     ( head -c number ) | ( cat > file; cat >/dev/null )
     *
     *  If `head' is not present on the remote system, `dd' will be used.
     * Unfortunately, we cannot trust most non-GNU `head' implementations
     * even if `-c' options is supported. Therefore, we separate GNU head
     * (and other modern heads?) using `-q' and `-' . This causes another
     * implementations to fail (because of "incorrect options").
     *
     *	Fallback is:
     *
     *	   rest=<number>
     *	   while [ $rest -gt 0 ]
     *	   do
     *	      cnt=`expr \( $rest + 255 \) / 256`
     *	      n=`dd bs=256 count=$cnt | tee -a <target_file> | wc -c`
     *	      rest=`expr $rest - $n`
     *	   done
     *
     *	`dd' was not designed for full filling of input buffers,
     *	and does not report exact number of bytes (not blocks).
     *	Therefore a more complex shell script is needed.
     *
     *	 On some systems non-GNU head writes "Usage:" error report to stdout
     *	instead of stderr. It makes impossible the use of "head || dd"
     *	algorithm for file appending case, therefore just "dd" is used for it.
     */

    print_vfs_message(_("fish: store %s: sending command..."), name );
    quoted_name = name_quote (name, 0);

    /* FIXME: File size is limited to ULONG_MAX */
    if (!fh->u.fish.append)
	n = fish_command (me, super, WAIT_REPLY,
		 "#STOR %lu /%s\n"
		 "echo '### 001'\n"
		 "file=/%s\n"
                 "res=`exec 3>&1\n"
		 "(\n"
		   "head -c %lu -q - || echo DD >&3\n"
		 ") 2>/dev/null | (\n"
		   "cat > \"$file\"\n"
		   "cat > /dev/null\n"
		 ")`; [ \"$res\" = DD ] && {\n"
			"> \"$file\"\n"
			"rest=%lu\n"
			"while [ $rest -gt 0 ]\n"
			"do\n"
			"    cnt=`expr \\( $rest + 255 \\) / 256`\n"
			"    n=`dd bs=256 count=$cnt | tee -a \"$file\" | wc -c`\n"
			"    rest=`expr $rest - $n`\n"
			"done\n"
		 "}; echo '### 200'\n",
		 (unsigned long) s.st_size, name,
		 quoted_name, (unsigned long) s.st_size,
		 (unsigned long) s.st_size);
    else
	n = fish_command (me, super, WAIT_REPLY,
		 "#STOR %lu /%s\n"
		 "echo '### 001'\n"
		 "{\n"
			"file=/%s\n"
			"rest=%lu\n"
			"while [ $rest -gt 0 ]\n"
			"do\n"
			"    cnt=`expr \\( $rest + 255 \\) / 256`\n"
			"    n=`dd bs=256 count=$cnt | tee -a \"$file\" | wc -c`\n"
			"    rest=`expr $rest - $n`\n"
			"done\n"
		 "}; echo '### 200'\n",
		 (unsigned long) s.st_size, name,
		 quoted_name, (unsigned long) s.st_size);

    g_free (quoted_name);
    if (n != PRELIM) {
	close (h);
        ERRNOR(E_REMOTE, -1);
    }
    total = 0;
    
    while (1) {
	int t;
	while ((n = read(h, buffer, sizeof(buffer))) < 0) {
	    if ((errno == EINTR) && got_interrupt())
	        continue;
	    print_vfs_message(_("fish: Local read failed, sending zeros") );
	    close(h);
	    h = open( "/dev/zero", O_RDONLY );
	}
	if (n == 0)
	    break;
    	if ((t = write (SUP.sockw, buffer, n)) != n) {
	    if (t == -1) {
		me->verrno = errno;
	    } else { 
		me->verrno = EIO;
	    }
	    goto error_return;
	}
	disable_interrupt_key();
	total += n;
	print_vfs_message(_("fish: storing %s %d (%lu)"), 
			  was_error ? _("zeros") : _("file"), total,
			  (unsigned long) s.st_size);
    }
    close(h);
    if ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error)
        ERRNOR (E_REMOTE, -1);
    return 0;
error_return:
    close(h);
    fish_get_reply(me, SUP.sockr, NULL, 0);
    return -1;
}
示例#11
0
文件: fish.c 项目: dborca/mc
static int
fish_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
{
    {
	const char *argv[10];
	const int port_num = SUP.flags &  0xFFFF;
	const int sh_flags = SUP.flags & ~0xFFFF;
	const char *xsh = (sh_flags == FISH_FLAG_RSH ? "rsh" : "ssh");
	char buf[8];
	int i = 0;

	argv[i++] = xsh;
	if (sh_flags == FISH_FLAG_COMPRESSED)
	    argv[i++] = "-C";
	if (port_num) {
	    sprintf(buf, "%d", port_num);
	    argv[i++] = "-p";
	    argv[i++] = buf;
	}
	argv[i++] = "-l";
	argv[i++] = SUP.user;
	argv[i++] = SUP.host;
	argv[i++] = "echo FISH:; /bin/sh";
	argv[i++] = NULL;

	fish_pipeopen (super, xsh, argv);
    }
    {
	char answer[2048];
	print_vfs_message (_("fish: Waiting for initial line..."));
	if (!vfs_s_get_line (me, SUP.sockr, answer, sizeof (answer), ':'))
	    ERRNOR (E_PROTO, -1);
	print_vfs_message ("%s", answer);
	if (strstr (answer, "assword")) {

	    /* Currently, this does not work. ssh reads passwords from
	       /dev/tty, not from stdin :-(. */

	    message (1, MSG_ERROR,
		     _
		     ("Sorry, we cannot do password authenticated connections for now."));
	    ERRNOR (EPERM, -1);
	    if (!SUP.password) {
		char *p, *op;
		p = g_strconcat (_(" fish: Password required for "),
				 SUP.user, " ", (char *) NULL);
		op = vfs_get_password (p);
		g_free (p);
		if (op == NULL)
		    ERRNOR (EPERM, -1);
		SUP.password = op;
	    }
	    print_vfs_message (_("fish: Sending password..."));
	    write (SUP.sockw, SUP.password, strlen (SUP.password));
	    write (SUP.sockw, "\n", 1);
	}
    }

    print_vfs_message (_("fish: Sending initial line..."));
    /*
     * Run `start_fish_server'. If it doesn't exist - no problem,
     * we'll talk directly to the shell.
     */
    if (fish_command
	(me, super, WAIT_REPLY,
	 "#FISH\necho; start_fish_server 2>&1; echo '### 200'\n") !=
	COMPLETE)
	ERRNOR (E_PROTO, -1);

    print_vfs_message (_("fish: Handshaking version..."));
    if (fish_command
	(me, super, WAIT_REPLY,
	 "#VER 0.0.0\necho '### 000'\n") != COMPLETE)
	ERRNOR (E_PROTO, -1);

    /* Set up remote locale to C, otherwise dates cannot be recognized */
    if (fish_command
	(me, super, WAIT_REPLY,
	 "LANG=C; LC_ALL=C; LC_TIME=C\n"
	 "export LANG; export LC_ALL; export LC_TIME\n" "echo '### 200'\n")
	!= COMPLETE)
	ERRNOR (E_PROTO, -1);

    print_vfs_message (_("fish: Setting up current directory..."));
    SUP.cwdir = fish_getcwd (me, super);
    print_vfs_message (_("fish: Connected, home %s."), SUP.cwdir);
#if 0
    super->name =
	g_strconcat ("/#sh:", SUP.user, "@", SUP.host, "/", (char *) NULL);
#endif
    super->name = g_strdup (PATH_SEP_STR);

    super->root =
	vfs_s_new_inode (me, super,
			 vfs_s_default_stat (me, S_IFDIR | 0755));
    return 0;
}
示例#12
0
文件: fish.c 项目: dborca/mc
/* The returned directory should always contain a trailing slash */
static char *fish_getcwd(struct vfs_class *me, struct vfs_s_super *super)
{
    if (fish_command (me, super, WANT_STRING, "#PWD\npwd; echo '### 200'\n") == COMPLETE)
        return  g_strconcat (reply_str, "/", (char *) NULL);
    ERRNOR (EIO, NULL);
}
static int tar_fh_open (vfs *me, vfs_s_fh *fh, int flags, int mode)
{
    if ((flags & O_ACCMODE) != O_RDONLY) ERRNOR (EROFS, -1);
    return 0;
}