⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 file.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:

    while ((next = mc_readdir (reading)) && return_status != FILE_ABORT){
        /*
         * Now, we don't want '.' and '..' to be created / copied at any time
         */
        if (!strcmp (next->d_name, "."))
            continue;
        if (!strcmp (next->d_name, ".."))
           continue;

        /* get the filename and add it to the src directory */
	path = concat_dir_and_file (s, next->d_name);

        (*xstat)(path, &buf);
        if (S_ISDIR (buf.st_mode)){
            mdpath = concat_dir_and_file (dest_dir, next->d_name);
            /*
             * From here, we just intend to recursively copy subdirs, not
             * the double functionality of copying different when the target
             * dir already exists. So, we give the recursive call the flag 0
             * meaning no toplevel.
             */
            return_status = copy_dir_dir (path, mdpath, 0, 0, delete, parent_dirs);
	    free (mdpath);
	} else {
	    dest_file = concat_dir_and_file (dest_dir, x_basename (path));
            return_status = copy_file_file (path, dest_file, 1);
	    free (dest_file);
	}
	if (delete && return_status == FILE_CONT) {
	    if (erase_at_end) {
                static struct link *tail;
		lp = xmalloc (sizeof (struct link) + strlen (path), "erase_list");
		strcpy (lp->name, path);
		lp->st_mode = buf.st_mode;
		lp->next = 0;
                if (erase_list) {
                   tail->next = lp;
                   tail = lp;
                } else
		   erase_list = tail = lp;
	    } else {
	        if (S_ISDIR (buf.st_mode)) {
		    return_status = erase_dir_iff_empty (path);
		} else
		    return_status = erase_file (path);
	    }
	}

#ifdef __os2__
	/* The OS/2 mc_readdir returns a block of memory DIR
	 * next should be freed: .ado
	 */
	if (!next)
		free (next);
#endif
        free (path);
    }
    mc_closedir (reading);

    /* .ado: Directories can not have permission set in OS/2 */
#ifndef __os2__
    if (preserve) {
	mc_chmod (dest_dir, cbuf.st_mode & umask_kill);
	utb.actime = cbuf.st_atime;
	utb.modtime = cbuf.st_mtime;
	mc_utime(dest_dir, &utb);
    }

#endif
ret:
    free (dest_dir);
    free (parent_dirs);
    return return_status;
}

/* }}} */

/* {{{ Move routines */

int
move_file_file (char *s, char *d)
{
    struct stat src_stats, dst_stats;
    int return_status = FILE_CONT;

    if (show_source (s) == FILE_ABORT
	|| show_target (d) == FILE_ABORT)
	return FILE_ABORT;

    mc_refresh ();

 retry_src_lstat:
    if (mc_lstat (s, &src_stats) != 0){
	/* Source doesn't exist */
	return_status = file_error (_(" Cannot stat file \"%s\" \n %s "), s);
	if (return_status == FILE_RETRY)
	    goto retry_src_lstat;
	return return_status;
    }

    if (mc_lstat (d, &dst_stats) == 0){
	/* Destination already exists */
	/* .ado: for OS/2 and NT, no st_ino exists */
#ifndef OS2_NT
	if (src_stats.st_dev == dst_stats.st_dev
	    && src_stats.st_ino == dst_stats.st_ino){
	    int msize = COLS - 36;
            char st[MC_MAXPATHLEN];
            char dt[MC_MAXPATHLEN];

	    if (msize < 0)
		msize = 40;
	    msize /= 2;

	    strcpy (st, name_trunc (s, msize));
	    strcpy (dt, name_trunc (d, msize));
	    message_3s (1, MSG_ERROR, _(" `%s' and `%s' are the same file "),
		     st, dt );
	    do_refresh ();
	    return FILE_SKIP;
	}
#endif /* OS2_NT */
	if (S_ISDIR (dst_stats.st_mode)){
	    message_2s (1, MSG_ERROR, _(" Cannot overwrite directory `%s' "), d);
	    do_refresh ();
	    return FILE_SKIP;
	}

	if (confirm_overwrite){
	    if (vfs_file_is_ftp (s))
		do_reget = -1;
	    else
		do_reget = 0;

	    return_status = query_replace (d, &src_stats, &dst_stats);
	    if (return_status != FILE_CONT)
		return return_status;
	}
	/* Ok to overwrite */
    }
#if 0
 retry_rename:
#endif
    if (!do_append) {
	if (S_ISLNK (src_stats.st_mode) && stable_symlinks) {
	    if ((return_status = make_symlink (s, d)) == FILE_CONT)
		goto retry_src_remove;
	    else
		return return_status;
	}

        if (mc_rename (s, d) == 0)
	    return FILE_CONT;
    }
#if 0
/* Comparison to EXDEV seems not to work in nfs if you're moving from
   one nfs to the same, but on the server it is on two different
   filesystems. Then nfs returns EIO instead of EXDEV.
   Hope it will not hurt if we always in case of error try to copy/delete. */
     else
    	errno = EXDEV; /* Hack to copy (append) the file and then delete it */

    if (errno != EXDEV){
	return_status = files_error (_(" Cannot move file \"%s\" to \"%s\" \n %s "), s, d);
	if (return_status == FILE_RETRY)
	    goto retry_rename;
	return return_status;
    }
#endif

    /* Failed because filesystem boundary -> copy the file instead */
    if ((return_status = copy_file_file (s, d, 0)) != FILE_CONT)
	return return_status;
    if ((return_status = show_source (NULL)) != FILE_CONT
	|| (return_status = show_file_progress (0, 0)) != FILE_CONT)
	return return_status;

    mc_refresh ();

 retry_src_remove:
    if (mc_unlink (s)){
	return_status = file_error (_(" Cannot remove file \"%s\" \n %s "), s);
	if (return_status == FILE_RETRY)
	    goto retry_src_remove;
	return return_status;
    }

    return FILE_CONT;
}

int
move_dir_dir (char *s, char *d)
{
    struct stat sbuf, dbuf, destbuf;
    struct link *lp;
    char *destdir;
    int return_status;
    int move_over = 0;

    if (show_source (s) == FILE_ABORT
	|| show_target (d) == FILE_ABORT)
	return FILE_ABORT;

    mc_refresh ();

    mc_stat (s, &sbuf);
    if (mc_stat (d, &dbuf))
	destdir = copy_strings (d, 0);  /* destination doesn't exist */
    else if (!dive_into_subdirs) {
	destdir = copy_strings (d, 0);
	move_over = 1;
    } else
	destdir = concat_dir_and_file (d, x_basename (s));

    /* Check if the user inputted an existing dir */
 retry_dst_stat:
    if (!mc_stat (destdir, &destbuf)){
	if (move_over) {
	    if ((return_status = copy_dir_dir (s, destdir, 0, 1, 1, 0)) != FILE_CONT)
		goto ret;
	    goto oktoret;
	} else {
	    if (S_ISDIR (destbuf.st_mode))
	        return_status = file_error (_(" Cannot overwrite directory \"%s\" %s "), destdir);
	    else
	        return_status = file_error (_(" Cannot overwrite file \"%s\" %s "), destdir);
	    if (return_status == FILE_RETRY)
	        goto retry_dst_stat;
	}
        free (destdir);
        return return_status;
    }

 retry_rename:
    if (mc_rename (s, destdir) == 0){
	return_status = FILE_CONT;
	goto ret;
    }
/* .ado: Drive, Do we need this anymore? */
#ifdef WIN32
        else {
        /* EXDEV: cross device; does not work everywhere */
                if (toupper(s[0]) != toupper(destdir[0]))
			goto w32try;
        }
#endif

    if (errno != EXDEV){
	return_status = files_error (_(" Cannot move directory \"%s\" to \"%s\" \n %s "), s, d);
	if (return_status == FILE_RETRY)
	    goto retry_rename;
	goto ret;
    }

w32try:
    /* Failed because of filesystem boundary -> copy dir instead */
    if ((return_status = copy_dir_dir (s, destdir, 0, 0, 1, 0)) != FILE_CONT)
	goto ret;
oktoret:
    if ((return_status = show_source (NULL)) != FILE_CONT
	|| (return_status = show_file_progress (0, 0)) != FILE_CONT)
	goto ret;

    mc_refresh ();
    if (erase_at_end) {
	for ( ; erase_list && return_status != FILE_ABORT; ) {
    	    if (S_ISDIR (erase_list->st_mode)) {
		return_status = erase_dir_iff_empty (erase_list->name);
	    } else
		return_status = erase_file (erase_list->name);
	    lp = erase_list;
	    erase_list = erase_list->next;
	    free (lp);
	}
    }
    erase_dir_iff_empty (s);

 ret:
    free (destdir);
    for ( ; erase_list; ) {
        lp = erase_list;
	erase_list = erase_list->next;
	free (lp);
    }
    return return_status;
}

/* }}} */

/* {{{ Erase routines */

static int
erase_file (char *s)
{
    int return_status;

    if (show_deleting (s) == FILE_ABORT)
	return FILE_ABORT;

    mc_refresh ();

 retry_unlink:
    if (mc_unlink (s)){
	return_status = file_error (_(" Cannot delete file \"%s\" \n %s "), s);
	if (return_status == FILE_RETRY)
	    goto retry_unlink;
	return return_status;
    }
    return FILE_CONT;
}

static int
recursive_erase (char *s)
{
    struct dirent *next;
    struct stat	buf;
    DIR    *reading;
    char   *path;
    int    return_status = FILE_CONT;

    if (!strcmp (s, ".."))
	return 1;

    reading = mc_opendir (s);

    if (!reading)
	return 1;

    while ((next = mc_readdir (reading)) && return_status == FILE_CONT){
	if (!strcmp (next->d_name, "."))
	    continue;
   	if (!strcmp (next->d_name, ".."))
	    continue;
	path = concat_dir_and_file (s, next->d_name);
   	if (mc_lstat (path, &buf)){
	    free (path);
	    return 1;
	}
	if (S_ISDIR (buf.st_mode))
	    return_status = (recursive_erase (path) != FILE_CONT);
	else
	    return_status = erase_file (path);
	free (path);
	/* .ado: OS/2 returns a block of memory DIR to next and must be freed */
#ifdef __os2__
	if (!next)
	    free (next);
#endif
    }
    mc_closedir (reading);
    if (return_status != FILE_CONT)
	return return_status;
    if (show_deleting (s) == FILE_ABORT)
	return FILE_ABORT;
    mc_refresh ();
 retry_rmdir:
    if (my_rmdir (s)){
	return_status = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
	if (return_status == FILE_RETRY)
	    goto retry_rmdir;
	return return_status;
    }
    return FILE_CONT;
}

/* Return -1 on error, 1 if there are no entries besides "." and ".."
   in the directory path points to, 0 else. */
static int
check_dir_is_empty(char *path)
{
    DIR *dir;
    struct dirent *d;
    int i;

    dir = mc_opendir (path);
    if (!dir)
	return -1;

    for (i = 1, d = mc_readdir (dir); d; d = mc_readdir (dir)) {
	if (d->d_name[0] == '.' && (d->d_name[1] == '\0' ||
            (d->d_name[1] == '.' && d->d_name[2] == '\0')))
	    continue; /* "." or ".." */
	i = 0;
	break;
    }

    mc_closedir (dir);
    return i;
}

int
erase_dir (char *s)
{
    int error;

    if (strcmp (s, "..") == 0)
	return FILE_SKIP;

    if (strcmp (s, ".") == 0)
	return FILE_SKIP;

    if (show_deleting (s) == FILE_ABORT)
	return FILE_ABORT;
    mc_refresh ();

    /* The old way to detect a non empty directory was:
            error = my_rmdir (s);
            if (error && (errno == ENOTEMPTY || errno == EEXIST))) {
       For the linux user space nfs server (nfs-server-2.2beta29-2)
       we would have to check also for EIO. I hope the new way is
       fool proof. (Norbert)
     */
    error = check_dir_is_empty (s);
    if (error == 0) { /* not empty */
	error = query_recursive (s);
	if (error == FILE_CONT)
	    return recursive_erase (s);
	else
	    return error;
    }

 retry_rmdir:
    error = my_rmdir (s);
    if (error == -1){
	error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
	if (error == FILE_RETRY)
	    goto retry_rmdir;
	return error;
    }
    return FILE_CONT;
}

int
erase_dir_iff_empty (char *s)
{
    int error;

    if (strcmp (s, "..") == 0)
	return FILE_SKIP;

    if (strcmp (s, ".") == 0)
	return FILE_SKIP;

    if (show_deleting (s) == FILE_ABORT)
	return FILE_ABORT;
    mc_refresh ();

    if (1 != check_dir_is_empty (s)) /* not empty or error */
	return FILE_CONT;

 retry_rmdir:
    error = my_rmdir (s);
    if (error) {
	error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
	if (error == FILE_RETRY)
	    goto retry_rmdir;
	return error;
    }
    return FILE_CONT;
}

/* }}} */

/* {{{ Panel operate routines */

/* Returns currently selected file or the first marked file if there is one */
static char *
get_file (WPanel *panel, struct stat *stat_buf)
{
    int i;

    /* No problem with Gnome, as get_current_type never returns view_tree there */
    if (get_current_type () == view_tree){
	WTree *tree = (WTree *)get_panel_widget (get_current_index ());

	mc_stat (tree->selected_ptr->name, stat_buf);
	return tree->selected_ptr->name;
    }

    if (panel->marked){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -