Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 94 additions & 39 deletions src/framework/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1396,32 +1396,86 @@ chsrc_run_directly (const char *cmd)
FILE *
chsrc_make_tmpfile (char *filename, char *postfix, bool loud, char **tmpfilepath)
{
char *tmpfile = NULL;
FILE *f = NULL;

#ifdef XY_Build_On_Windows
/**
* Windows 上没有 mkstemps(),只有 mkstemp() 和 _mktemp_s(),这后两者效果是等价的,只不过传参不同,
* 这意味着我们无法给一个文件名后缀(postfix),只能生成一个临时文件名
* 然而 PowerShell 的执行,即使加了 -File 参数,也必须要求你拥有 .ps1 后缀
* 这使得我们在 Windows 上只能创建一个假的临时文件
* Windows 上使用 GetTempPath 和 GetTempFileName 创建临时文件
* 这是 Windows API 推荐的标准方法
*
* 由于 GetTempFileName 不支持自定义后缀,我们需要:
* 1. 使用 GetTempFileName 生成唯一的临时文件名
* 2. 将其重命名为带有正确后缀的文件名(PowerShell 需要 .ps1 后缀)
*/
char *tmpfile = xy_strcat (3, "chsrc_tmp_", filename, postfix);
FILE *f = fopen (tmpfile, "w+");
char temp_path[MAX_PATH];
char temp_filename[MAX_PATH];

/* 获取系统临时目录 */
DWORD ret = GetTempPathA (MAX_PATH, temp_path);
if (ret == 0 || ret > MAX_PATH)
{
char *msg = CHINESE ? "无法获取系统临时目录" : "Unable to get system temp directory";
chsrc_error2 (msg);
exit (Exit_ExternalError);
}

/* 生成唯一的临时文件名 (会自动创建文件) */
ret = GetTempFileNameA (temp_path, "chsrc_", 0, temp_filename);
if (ret == 0)
{
char *msg = CHINESE ? "无法生成临时文件名" : "Unable to generate temporary filename";
chsrc_error2 (msg);
exit (Exit_ExternalError);
}

tmpfile = xy_strcat (4, temp_filename, "_", filename, postfix);

/* 删除 GetTempFileName 自动创建的文件 */
DeleteFileA (temp_filename);

/* 创建带有正确后缀的文件 */
f = fopen (tmpfile, "w+");

if (!f)
{
char *msg = CHINESE ? "无法创建临时文件: " : "Unable to create temporary file: ";
msg = xy_2strcat (msg, tmpfile);
chsrc_error2 (msg);
exit (Exit_ExternalError);
}
#else
char *tmpfile = xy_strcat (5, "/tmp/", "chsrc_tmp_", filename, "_XXXXXX", postfix);
/**
* 非 Windows 平台使用 mkstemps() 创建临时文件
* 这是 POSIX 标准方法,可以指定后缀名
*/
tmpfile = xy_strcat (5, "/tmp/", "chsrc_tmp_", filename, "_XXXXXX", postfix);
size_t postfix_len = strlen (postfix);

/* 和 _mktemp_s() 参数不同,前者是整个缓存区大小,这里的长度是后缀长度 */
/* mkstemps() 会原子性地创建文件并返回文件描述符 */
int fd = mkstemps (tmpfile, postfix_len);
FILE *f = fdopen (fd, "w+");
#endif

if (!f)
if (fd == -1)
{
char *msg = CHINESE ? "无法创建临时文件: " : "Unable to create temporary file: ";
msg = xy_2strcat (msg, tmpfile);
chsrc_error2 (msg);
exit (Exit_ExternalError);
}
else if (loud)

f = fdopen (fd, "w+");

if (!f)
{
close (fd); /* 关闭文件描述符以避免泄漏 */
char *msg = CHINESE ? "无法打开临时文件: " : "Unable to open temporary file: ";
msg = xy_2strcat (msg, tmpfile);
chsrc_error2 (msg);
exit (Exit_ExternalError);
}
#endif

if (loud)
{
char *msg = CHINESE ? "已创建临时文件: " : "Temporary file created: ";
msg = xy_2strcat (msg, tmpfile);
Expand Down Expand Up @@ -1705,65 +1759,66 @@ chsrc_prepend_to_file (const char *str, const char *filename)
char *dir = xy_parent_dir (file);
chsrc_ensure_dir (dir);

char *tmpfile_name = "prepend";
char *tmpfile_ext = ".txt";
char *tmpnull = "";
FILE *tmp = chsrc_make_tmpfile (tmpfile_name, tmpfile_ext, true, &tmpnull);
fclose (tmp);
char *temp_file = xy_strcat (3, "chsrc_tmp_", tmpfile_name, tmpfile_ext);

FILE *input = fopen (file, "r");
FILE *output = fopen (temp_file, "w");
char *tmpfile_path = NULL;
FILE *output = chsrc_make_tmpfile ("prepend", ".txt", false, &tmpfile_path);

if (!output)
{
if (input) fclose (input);
free (temp_file);
char *msg = ENGLISH ? xy_2strcat ("Create temp file before Write prepend failed ", file)
: xy_2strcat ("尝试在文件开头写入时创建临时文件失败:", file);
chsrc_error2 (msg);
exit (Exit_ExternalError);
}

// 先写入要插入的行
/* 先写入要插入的内容 */
fprintf (output, "%s", str);

// 如果原文件存在,复制其内容
/* 如果原文件存在,复制其内容到临时文件 */
FILE *input = fopen (file, "r");
if (input)
{
fseek (input, 0, SEEK_END);
long file_size = ftell (input);
fseek (input, 0, SEEK_SET);

char *buffer = malloc(file_size);
if (buffer == NULL)
if (file_size > 0)
{
fclose (input);
return;
}

size_t bytes = fread(buffer, 1, file_size, input);
if (bytes > 0) fwrite(buffer, 1, bytes, output);
char *buffer = malloc (file_size);
if (buffer == NULL)
{
fclose (input);
fclose (output);
remove (tmpfile_path);
char *msg = ENGLISH ? "Memory allocation failed" : "内存分配失败";
chsrc_error2 (msg);
exit (Exit_ExternalError);
}

free (buffer);
size_t bytes = fread (buffer, 1, file_size, input);
if (bytes > 0)
{
fwrite (buffer, 1, bytes, output);
}
free (buffer);
}
fclose (input);
}

fclose (output);

/* 删除原文件(如果存在) */
remove (file);

if (rename (temp_file, file) != 0)
/* 将临时文件重命名为目标文件 */
if (rename (tmpfile_path, file) != 0)
{
unlink (temp_file);
free (temp_file);
unlink (tmpfile_path);
char *msg = ENGLISH ? xy_2strcat ("Write prepend failed to ", file)
: xy_2strcat ("在文件开头写入失败: ", file);
chsrc_error2 (msg);
exit (Exit_ExternalError);
}

free (temp_file);

log_anyway:
/* 输出recipe指定的文件名 */
chsrc_log_write (filename, false);
Expand Down
Loading