mirror of
https://github.com/MidnightCommander/mc
synced 2025-01-03 01:54:24 +03:00
Handle hard link creation error.
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
parent
0f0dbc2b2e
commit
2c2e41c167
@ -124,6 +124,17 @@ typedef enum
|
|||||||
DEST_FULL = 2 /* Created, fully copied */
|
DEST_FULL = 2 /* Created, fully copied */
|
||||||
} dest_status_t;
|
} dest_status_t;
|
||||||
|
|
||||||
|
/* Status of hard link creation */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
HARDLINK_OK = 0, /**< Hardlink was created successfully */
|
||||||
|
HARDLINK_CACHED, /**< Hardlink was added to the cache */
|
||||||
|
HARDLINK_NOTLINK, /**< This is not a hard link */
|
||||||
|
HARDLINK_UNSUPPORTED, /**< VFS doesn't support hard links */
|
||||||
|
HARDLINK_ERROR, /**< Hard link creation error */
|
||||||
|
HARDLINK_ABORT /**< Stop file operation after hardlink creation error */
|
||||||
|
} hardlink_status_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This array introduced to avoid translation problems. The former (op_names)
|
* This array introduced to avoid translation problems. The former (op_names)
|
||||||
* is assumed to be nouns, suitable in dialog box titles; this one should
|
* is assumed to be nouns, suitable in dialog box titles; this one should
|
||||||
@ -332,16 +343,18 @@ is_in_linklist (const GSList * lp, const vfs_path_t * vpath, const struct stat *
|
|||||||
* and a hardlink was successfully made
|
* and a hardlink was successfully made
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static gboolean
|
static hardlink_status_t
|
||||||
check_hardlinks (const vfs_path_t * src_vpath, const struct stat *src_stat,
|
check_hardlinks (const vfs_path_t * src_vpath, const struct stat *src_stat,
|
||||||
const vfs_path_t * dst_vpath)
|
const vfs_path_t * dst_vpath, gboolean * skip_all)
|
||||||
{
|
{
|
||||||
struct link *lnk;
|
struct link *lnk;
|
||||||
ino_t ino = src_stat->st_ino;
|
ino_t ino = src_stat->st_ino;
|
||||||
dev_t dev = src_stat->st_dev;
|
dev_t dev = src_stat->st_dev;
|
||||||
|
|
||||||
if (src_stat->st_nlink < 2 || (vfs_file_class_flags (src_vpath) & VFSF_NOLINKS) != 0)
|
if (src_stat->st_nlink < 2)
|
||||||
return FALSE;
|
return HARDLINK_NOTLINK;
|
||||||
|
if ((vfs_file_class_flags (src_vpath) & VFSF_NOLINKS) != 0)
|
||||||
|
return HARDLINK_UNSUPPORTED;
|
||||||
|
|
||||||
lnk = (struct link *) is_in_linklist (linklist, src_vpath, src_stat);
|
lnk = (struct link *) is_in_linklist (linklist, src_vpath, src_stat);
|
||||||
if (lnk != NULL)
|
if (lnk != NULL)
|
||||||
@ -366,15 +379,82 @@ check_hardlinks (const vfs_path_t * src_vpath, const struct stat *src_stat,
|
|||||||
dst_name_class = vfs_path_get_last_path_vfs (dst_vpath);
|
dst_name_class = vfs_path_get_last_path_vfs (dst_vpath);
|
||||||
p_class = vfs_path_get_last_path_vfs (lnk->dst_vpath);
|
p_class = vfs_path_get_last_path_vfs (lnk->dst_vpath);
|
||||||
|
|
||||||
if (dst_name_class == p_class && mc_stat (lnk->dst_vpath, &link_stat) == 0 &&
|
if (dst_name_class == p_class)
|
||||||
mc_link (lnk->dst_vpath, dst_vpath) == 0)
|
{
|
||||||
return TRUE;
|
gboolean ok;
|
||||||
|
|
||||||
|
while (!(ok = mc_stat (lnk->dst_vpath, &link_stat) == 0) && !*skip_all)
|
||||||
|
{
|
||||||
|
FileProgressStatus status;
|
||||||
|
|
||||||
|
status =
|
||||||
|
file_error (TRUE, _("Cannot stat hardlink source file \"%s\"\n%s"),
|
||||||
|
vfs_path_as_str (lnk->dst_vpath));
|
||||||
|
if (status == FILE_ABORT)
|
||||||
|
return HARDLINK_ABORT;
|
||||||
|
if (status == FILE_RETRY)
|
||||||
|
continue;
|
||||||
|
if (status == FILE_SKIPALL)
|
||||||
|
*skip_all = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if stat() finished unsuccessfully, don't try to create link */
|
||||||
|
if (!ok)
|
||||||
|
return HARDLINK_ERROR;
|
||||||
|
|
||||||
|
while (!(ok = mc_link (lnk->dst_vpath, dst_vpath) == 0) && !*skip_all)
|
||||||
|
{
|
||||||
|
FileProgressStatus status;
|
||||||
|
|
||||||
|
status =
|
||||||
|
file_error (TRUE, _("Cannot create target hardlink \"%s\"\n%s"),
|
||||||
|
vfs_path_as_str (dst_vpath));
|
||||||
|
if (status == FILE_ABORT)
|
||||||
|
return HARDLINK_ABORT;
|
||||||
|
if (status == FILE_RETRY)
|
||||||
|
continue;
|
||||||
|
if (status == FILE_SKIPALL)
|
||||||
|
*skip_all = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success? */
|
||||||
|
return (ok ? HARDLINK_OK : HARDLINK_ERROR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message (D_ERROR, MSG_ERROR, _("Cannot make the hardlink\n%s\nto\n%s"),
|
if (!*skip_all)
|
||||||
vfs_path_as_str (dst_vpath), vfs_path_as_str (lnk->dst_vpath));
|
{
|
||||||
return FALSE;
|
FileProgressStatus status;
|
||||||
|
|
||||||
|
/* Message w/o "Retry" action.
|
||||||
|
*
|
||||||
|
* FIXME: Can't say what errno is here. Define it and don't display.
|
||||||
|
*
|
||||||
|
* file_error() displays a message with text representation of errno
|
||||||
|
* and the string passed to file_error() should provide the format "%s"
|
||||||
|
* for that at end (see previous file_error() call for the reference).
|
||||||
|
* But if format for errno isn't provided, it is safe, because C standard says:
|
||||||
|
* "If the format is exhausted while arguments remain, the excess arguments
|
||||||
|
* are evaluated (as always) but are otherwise ignored" (ISO/IEC 9899:1999,
|
||||||
|
* section 7.19.6.1, paragraph 2).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
errno = 0;
|
||||||
|
status =
|
||||||
|
file_error (FALSE, _("Cannot create target hardlink \"%s\""),
|
||||||
|
vfs_path_as_str (dst_vpath));
|
||||||
|
|
||||||
|
if (status == FILE_ABORT)
|
||||||
|
return HARDLINK_ABORT;
|
||||||
|
|
||||||
|
if (status == FILE_SKIPALL)
|
||||||
|
*skip_all = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HARDLINK_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
lnk = g_try_new (struct link, 1);
|
lnk = g_try_new (struct link, 1);
|
||||||
@ -391,7 +471,7 @@ check_hardlinks (const vfs_path_t * src_vpath, const struct stat *src_stat,
|
|||||||
linklist = g_slist_prepend (linklist, lnk);
|
linklist = g_slist_prepend (linklist, lnk);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return HARDLINK_CACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
@ -2201,11 +2281,22 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx,
|
|||||||
if (!ctx->do_append)
|
if (!ctx->do_append)
|
||||||
{
|
{
|
||||||
/* Check the hardlinks */
|
/* Check the hardlinks */
|
||||||
if (!ctx->follow_links && check_hardlinks (src_vpath, &src_stat, dst_vpath))
|
if (!ctx->follow_links)
|
||||||
{
|
{
|
||||||
/* We have made a hardlink - no more processing is necessary */
|
switch (check_hardlinks (src_vpath, &src_stat, dst_vpath, &ctx->skip_all))
|
||||||
return_status = FILE_CONT;
|
{
|
||||||
goto ret_fast;
|
case HARDLINK_OK:
|
||||||
|
/* We have made a hardlink - no more processing is necessary */
|
||||||
|
return_status = FILE_CONT;
|
||||||
|
goto ret_fast;
|
||||||
|
|
||||||
|
case HARDLINK_ABORT:
|
||||||
|
return_status = FILE_ABORT;
|
||||||
|
goto ret_fast;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISLNK (src_stat.st_mode))
|
if (S_ISLNK (src_stat.st_mode))
|
||||||
@ -2708,10 +2799,21 @@ copy_dir_dir (file_op_total_context_t * tctx, file_op_context_t * ctx, const cha
|
|||||||
/* Hmm, hardlink to directory??? - Norbert */
|
/* Hmm, hardlink to directory??? - Norbert */
|
||||||
/* FIXME: In this step we should do something in case the destination already exist */
|
/* FIXME: In this step we should do something in case the destination already exist */
|
||||||
/* Check the hardlinks */
|
/* Check the hardlinks */
|
||||||
if (ctx->preserve && check_hardlinks (src_vpath, &cbuf, dst_vpath))
|
if (ctx->preserve)
|
||||||
{
|
{
|
||||||
/* We have made a hardlink - no more processing is necessary */
|
switch (check_hardlinks (src_vpath, &cbuf, dst_vpath, &ctx->skip_all))
|
||||||
goto ret_fast;
|
{
|
||||||
|
case HARDLINK_OK:
|
||||||
|
/* We have made a hardlink - no more processing is necessary */
|
||||||
|
goto ret_fast;
|
||||||
|
|
||||||
|
case HARDLINK_ABORT:
|
||||||
|
return_status = FILE_ABORT;
|
||||||
|
goto ret_fast;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!S_ISDIR (cbuf.st_mode))
|
if (!S_ISDIR (cbuf.st_mode))
|
||||||
|
Loading…
Reference in New Issue
Block a user