rework the file-writing routines so that they can work properly with
already-opened files, such as the mkstemp()-created files used by the spell-checking code git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2571 35c25a1d-7b9e-4130-9fde-d3aeb78583b8master
parent
bec2f20da0
commit
5e068c6031
|
@ -40,6 +40,12 @@ CVS code -
|
||||||
necessary. Changes to get_next_filename(), write_file(),
|
necessary. Changes to get_next_filename(), write_file(),
|
||||||
die(), usage(), nano.1, nanorc.5, nanorc.sample, and
|
die(), usage(), nano.1, nanorc.5, nanorc.sample, and
|
||||||
nano.texi. (DLR, suggested by James Collings)
|
nano.texi. (DLR, suggested by James Collings)
|
||||||
|
- Rework the file-writing routines so that they can work
|
||||||
|
properly with already-opened files, such as the
|
||||||
|
mkstemp()-created files used by the spell-checking code.
|
||||||
|
Changes to safe_tempnam() (renamed safe_tempfile()),
|
||||||
|
write_file(), write_marked(), die(), do_spell(), and
|
||||||
|
do_exit(). (DLR)
|
||||||
- cut.c:
|
- cut.c:
|
||||||
cut_line()
|
cut_line()
|
||||||
- Set placewewant properly after cutting a line, to avoid a
|
- Set placewewant properly after cutting a line, to avoid a
|
||||||
|
|
117
src/files.c
117
src/files.c
|
@ -1134,15 +1134,18 @@ char *check_writable_directory(const char *path)
|
||||||
return full_path;
|
return full_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function acts like a call to tempnam(NULL, "nano."). The
|
/* This function calls mkstemp(($TMPDIR|P_tmpdir|/tmp/)"nano.XXXXXX").
|
||||||
* difference is that the number of calls is not limited by TMP_MAX.
|
* On success, it returns the malloc()ed filename and corresponding FILE
|
||||||
* Instead we use mkstemp(). */
|
* stream, opened in "w+b" mode. On error, it returns NULL for the
|
||||||
char *safe_tempnam(void)
|
* filename and leaves the FILE stream unchanged. */
|
||||||
|
char *safe_tempfile(FILE **f)
|
||||||
{
|
{
|
||||||
char *full_tempdir = NULL;
|
char *full_tempdir = NULL;
|
||||||
const char *TMPDIR_env;
|
const char *TMPDIR_env;
|
||||||
int filedesc;
|
int filedesc;
|
||||||
|
|
||||||
|
assert(f != NULL);
|
||||||
|
|
||||||
/* If $TMPDIR is set and non-empty, set tempdir to it, run it
|
/* If $TMPDIR is set and non-empty, set tempdir to it, run it
|
||||||
* through get_full_path(), and save the result in full_tempdir.
|
* through get_full_path(), and save the result in full_tempdir.
|
||||||
* Otherwise, leave full_tempdir set to NULL. */
|
* Otherwise, leave full_tempdir set to NULL. */
|
||||||
|
@ -1163,17 +1166,14 @@ char *safe_tempnam(void)
|
||||||
strcat(full_tempdir, "nano.XXXXXX");
|
strcat(full_tempdir, "nano.XXXXXX");
|
||||||
filedesc = mkstemp(full_tempdir);
|
filedesc = mkstemp(full_tempdir);
|
||||||
|
|
||||||
/* If mkstemp() succeeded, close the resulting file, delete it
|
if (filedesc != -1)
|
||||||
* (since it'll be 0 bytes long), and return the filename. */
|
*f = fdopen(filedesc, "w+b");
|
||||||
if (filedesc != -1) {
|
else {
|
||||||
close(filedesc);
|
free(full_tempdir);
|
||||||
unlink(full_tempdir);
|
full_tempdir = NULL;
|
||||||
return full_tempdir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(full_tempdir);
|
return full_tempdir;
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
#endif /* !DISABLE_SPELLER */
|
#endif /* !DISABLE_SPELLER */
|
||||||
|
|
||||||
|
@ -1304,10 +1304,11 @@ int copy_file(FILE *inn, FILE *out)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a file out. If tmp is FALSE, we set the umask to disallow
|
/* Write a file out. If f_open isn't NULL, we assume that it is a
|
||||||
* anyone else from accessing the file, we don't set the global variable
|
* stream associated with the file, and we don't try to open it
|
||||||
* filename to its name, and we don't print out how many lines we wrote
|
* ourselves. If tmp is TRUE, we set the umask to disallow anyone else
|
||||||
* on the statusbar.
|
* from accessing the file, we don't set the global variable filename to
|
||||||
|
* its name, and we don't print out how many lines we wrote on the statusbar.
|
||||||
*
|
*
|
||||||
* tmp means we are writing a temporary file in a secure fashion. We
|
* tmp means we are writing a temporary file in a secure fashion. We
|
||||||
* use it when spell checking or dumping the file on an error.
|
* use it when spell checking or dumping the file on an error.
|
||||||
|
@ -1318,9 +1319,9 @@ int copy_file(FILE *inn, FILE *out)
|
||||||
* nonamechange means don't change the current filename. It is ignored
|
* nonamechange means don't change the current filename. It is ignored
|
||||||
* if tmp is FALSE or if we're appending/prepending.
|
* if tmp is FALSE or if we're appending/prepending.
|
||||||
*
|
*
|
||||||
* Return -1 on error, 1 on success. */
|
* Return 0 on success or -1 on error. */
|
||||||
int write_file(const char *name, bool tmp, int append, bool
|
int write_file(const char *name, FILE *f_open, bool tmp, int append,
|
||||||
nonamechange)
|
bool nonamechange)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
/* Instead of returning in this function, you should always
|
/* Instead of returning in this function, you should always
|
||||||
|
@ -1344,7 +1345,7 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
/* The status fields filled in by lstat(). */
|
/* The status fields filled in by lstat(). */
|
||||||
char *realname;
|
char *realname;
|
||||||
/* name after tilde expansion. */
|
/* name after tilde expansion. */
|
||||||
FILE *f;
|
FILE *f = NULL;
|
||||||
/* The actual file, realname, we are writing to. */
|
/* The actual file, realname, we are writing to. */
|
||||||
char *tempname = NULL;
|
char *tempname = NULL;
|
||||||
/* The temp file name we write to on prepend. */
|
/* The temp file name we write to on prepend. */
|
||||||
|
@ -1354,6 +1355,9 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
if (name[0] == '\0')
|
if (name[0] == '\0')
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (f_open != NULL)
|
||||||
|
f = f_open;
|
||||||
|
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
titlebar(NULL);
|
titlebar(NULL);
|
||||||
|
|
||||||
|
@ -1370,8 +1374,8 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
|
|
||||||
anyexists = (lstat(realname, &lst) != -1);
|
anyexists = (lstat(realname, &lst) != -1);
|
||||||
|
|
||||||
/* If the temp file exists, give up. */
|
/* If the temp file exists and isn't already open, give up. */
|
||||||
if (tmp && anyexists)
|
if (tmp && anyexists && f_open == NULL)
|
||||||
goto cleanup_and_exit;
|
goto cleanup_and_exit;
|
||||||
|
|
||||||
/* If NOFOLLOW_SYMLINKS is set, it doesn't make sense to prepend or
|
/* If NOFOLLOW_SYMLINKS is set, it doesn't make sense to prepend or
|
||||||
|
@ -1404,6 +1408,7 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
filetime.actime = originalfilestat.st_atime;
|
filetime.actime = originalfilestat.st_atime;
|
||||||
filetime.modtime = originalfilestat.st_mtime;
|
filetime.modtime = originalfilestat.st_mtime;
|
||||||
|
|
||||||
|
if (f_open == NULL) {
|
||||||
/* Open the original file to copy to the backup. */
|
/* Open the original file to copy to the backup. */
|
||||||
f = fopen(realname, "rb");
|
f = fopen(realname, "rb");
|
||||||
|
|
||||||
|
@ -1412,6 +1417,7 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
goto cleanup_and_exit;
|
goto cleanup_and_exit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If backup_dir is set, we set backupname to
|
/* If backup_dir is set, we set backupname to
|
||||||
* backup_dir/backupname~[.number], where backupname is the
|
* backup_dir/backupname~[.number], where backupname is the
|
||||||
|
@ -1510,53 +1516,45 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
goto cleanup_and_exit;
|
goto cleanup_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (f_open == NULL) {
|
||||||
original_umask = umask(0);
|
original_umask = umask(0);
|
||||||
umask(original_umask);
|
umask(original_umask);
|
||||||
|
|
||||||
/* If we create a temp file, we don't let anyone else access it. We
|
/* If we create a temp file, we don't let anyone else access it.
|
||||||
* create a temp file if tmp is TRUE or if we're prepending. */
|
* We create a temp file if tmp is TRUE or if we're
|
||||||
|
* prepending. */
|
||||||
if (tmp || append == 2)
|
if (tmp || append == 2)
|
||||||
umask(S_IRWXG | S_IRWXO);
|
umask(S_IRWXG | S_IRWXO);
|
||||||
|
}
|
||||||
|
|
||||||
/* If we're prepending, copy the file to a temp file. */
|
/* If we're prepending, copy the file to a temp file. */
|
||||||
if (append == 2) {
|
if (append == 2) {
|
||||||
int fd_source;
|
int fd_source;
|
||||||
FILE *f_source = NULL;
|
FILE *f_source = NULL;
|
||||||
|
|
||||||
tempname = charalloc(strlen(realname) + 8);
|
tempname = safe_tempfile(&f);
|
||||||
strcpy(tempname, realname);
|
|
||||||
strcat(tempname, ".XXXXXX");
|
|
||||||
fd = mkstemp(tempname);
|
|
||||||
f = NULL;
|
|
||||||
|
|
||||||
if (fd != -1) {
|
if (tempname == NULL) {
|
||||||
f = fdopen(fd, "wb");
|
statusbar(_("Prepending to %s failed: %s"), realname,
|
||||||
if (f == NULL)
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f == NULL) {
|
|
||||||
statusbar(_("Error writing %s: %s"), tempname,
|
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
unlink(tempname);
|
|
||||||
goto cleanup_and_exit;
|
goto cleanup_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (f_open == NULL) {
|
||||||
fd_source = open(realname, O_RDONLY | O_CREAT);
|
fd_source = open(realname, O_RDONLY | O_CREAT);
|
||||||
|
|
||||||
if (fd_source != -1) {
|
if (fd_source != -1) {
|
||||||
f_source = fdopen(fd_source, "rb");
|
f_source = fdopen(fd_source, "rb");
|
||||||
if (f_source == NULL)
|
|
||||||
close(fd_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f_source == NULL) {
|
if (f_source == NULL) {
|
||||||
statusbar(_("Error reading %s: %s"), realname,
|
statusbar(_("Error reading %s: %s"), realname,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
close(fd_source);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
unlink(tempname);
|
unlink(tempname);
|
||||||
goto cleanup_and_exit;
|
goto cleanup_and_exit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (copy_file(f_source, f) != 0) {
|
if (copy_file(f_source, f) != 0) {
|
||||||
statusbar(_("Error writing %s: %s"), tempname,
|
statusbar(_("Error writing %s: %s"), tempname,
|
||||||
|
@ -1566,18 +1564,21 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now open the file in place. Use O_EXCL if tmp is TRUE. This is
|
if (f_open == NULL) {
|
||||||
* copied from joe, because wiggy says so *shrug*. */
|
/* Now open the file in place. Use O_EXCL if tmp is TRUE. This
|
||||||
|
* is copied from joe, because wiggy says so *shrug*. */
|
||||||
fd = open(realname, O_WRONLY | O_CREAT |
|
fd = open(realname, O_WRONLY | O_CREAT |
|
||||||
((append == 1) ? O_APPEND : (tmp ? O_EXCL : O_TRUNC)),
|
((append == 1) ? O_APPEND : (tmp ? O_EXCL : O_TRUNC)),
|
||||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
|
||||||
|
S_IWOTH);
|
||||||
|
|
||||||
/* Set the umask back to the user's original value. */
|
/* Set the umask back to the user's original value. */
|
||||||
umask(original_umask);
|
umask(original_umask);
|
||||||
|
|
||||||
/* If we couldn't open the file, give up. */
|
/* If we couldn't open the file, give up. */
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
statusbar(_("Error writing %s: %s"), realname, strerror(errno));
|
statusbar(_("Error writing %s: %s"), realname,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
/* tempname has been set only if we're prepending. */
|
/* tempname has been set only if we're prepending. */
|
||||||
if (tempname != NULL)
|
if (tempname != NULL)
|
||||||
|
@ -1588,10 +1589,12 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
f = fdopen(fd, (append == 1) ? "ab" : "wb");
|
f = fdopen(fd, (append == 1) ? "ab" : "wb");
|
||||||
|
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
statusbar(_("Error writing %s: %s"), realname, strerror(errno));
|
statusbar(_("Error writing %s: %s"), realname,
|
||||||
|
strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
goto cleanup_and_exit;
|
goto cleanup_and_exit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* There might not be a magicline. There won't be when writing out
|
/* There might not be a magicline. There won't be when writing out
|
||||||
* a selection. */
|
* a selection. */
|
||||||
|
@ -1692,7 +1695,7 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
titlebar(NULL);
|
titlebar(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = 1;
|
retval = 0;
|
||||||
|
|
||||||
cleanup_and_exit:
|
cleanup_and_exit:
|
||||||
free(realname);
|
free(realname);
|
||||||
|
@ -1704,11 +1707,11 @@ int write_file(const char *name, bool tmp, int append, bool
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
/* Write a marked selection from a file out. First, set fileage and
|
/* Write a marked selection from a file out. First, set fileage and
|
||||||
* filebot as the top and bottom of the mark, respectively. Then call
|
* filebot as the top and bottom of the mark, respectively. Then call
|
||||||
* write_file() with the values of name, temp, and append, and with
|
* write_file() with the values of name, f_open, temp, and append, and
|
||||||
* nonamechange set to TRUE so that we don't change the current
|
* with nonamechange set to TRUE so that we don't change the current
|
||||||
* filename. Finally, set fileage and filebot back to their old values
|
* filename. Finally, set fileage and filebot back to their old values
|
||||||
* and return. */
|
* and return. */
|
||||||
int write_marked(const char *name, bool tmp, int append)
|
int write_marked(const char *name, FILE *f_open, bool tmp, int append)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
bool old_modified = ISSET(MODIFIED);
|
bool old_modified = ISSET(MODIFIED);
|
||||||
|
@ -1731,7 +1734,7 @@ int write_marked(const char *name, bool tmp, int append)
|
||||||
if (added_magicline)
|
if (added_magicline)
|
||||||
new_magicline();
|
new_magicline();
|
||||||
|
|
||||||
retval = write_file(name, tmp, append, TRUE);
|
retval = write_file(name, f_open, tmp, append, TRUE);
|
||||||
|
|
||||||
/* If we added a magicline, remove it now. */
|
/* If we added a magicline, remove it now. */
|
||||||
if (added_magicline)
|
if (added_magicline)
|
||||||
|
@ -1761,10 +1764,10 @@ int do_writeout(bool exiting)
|
||||||
currshortcut = writefile_list;
|
currshortcut = writefile_list;
|
||||||
|
|
||||||
if (exiting && filename[0] != '\0' && ISSET(TEMP_FILE)) {
|
if (exiting && filename[0] != '\0' && ISSET(TEMP_FILE)) {
|
||||||
retval = write_file(filename, FALSE, 0, FALSE);
|
retval = write_file(filename, NULL, FALSE, 0, FALSE);
|
||||||
|
|
||||||
/* Write succeeded. */
|
/* Write succeeded. */
|
||||||
if (retval == 1)
|
if (retval == 0)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1907,10 +1910,10 @@ int do_writeout(bool exiting)
|
||||||
* disabled since it allows reading from or writing to files
|
* disabled since it allows reading from or writing to files
|
||||||
* not specified on the command line. */
|
* not specified on the command line. */
|
||||||
if (!ISSET(RESTRICTED) && !exiting && ISSET(MARK_ISSET))
|
if (!ISSET(RESTRICTED) && !exiting && ISSET(MARK_ISSET))
|
||||||
retval = write_marked(answer, FALSE, append);
|
retval = write_marked(answer, NULL, FALSE, append);
|
||||||
else
|
else
|
||||||
#endif /* !NANO_SMALL */
|
#endif /* !NANO_SMALL */
|
||||||
retval = write_file(answer, FALSE, append, FALSE);
|
retval = write_file(answer, NULL, FALSE, append, FALSE);
|
||||||
|
|
||||||
#ifdef ENABLE_MULTIBUFFER
|
#ifdef ENABLE_MULTIBUFFER
|
||||||
/* If we're not about to exit, update the current entry in
|
/* If we're not about to exit, update the current entry in
|
||||||
|
|
11
src/nano.c
11
src/nano.c
|
@ -171,7 +171,7 @@ void die_save_file(const char *die_filename)
|
||||||
|
|
||||||
retval = get_next_filename(die_filename, ".save");
|
retval = get_next_filename(die_filename, ".save");
|
||||||
if (retval[0] != '\0')
|
if (retval[0] != '\0')
|
||||||
failed = (write_file(retval, TRUE, FALSE, TRUE) == -1);
|
failed = (write_file(retval, NULL, TRUE, FALSE, TRUE) == -1);
|
||||||
|
|
||||||
if (!failed)
|
if (!failed)
|
||||||
fprintf(stderr, _("\nBuffer written to %s\n"), retval);
|
fprintf(stderr, _("\nBuffer written to %s\n"), retval);
|
||||||
|
@ -2368,7 +2368,8 @@ const char *do_alt_speller(char *tempfile_name)
|
||||||
void do_spell(void)
|
void do_spell(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *temp = safe_tempnam();
|
FILE *temp_file;
|
||||||
|
char *temp = safe_tempfile(&temp_file);
|
||||||
const char *spell_msg;
|
const char *spell_msg;
|
||||||
|
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
|
@ -2378,10 +2379,10 @@ void do_spell(void)
|
||||||
|
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
if (ISSET(MARK_ISSET))
|
if (ISSET(MARK_ISSET))
|
||||||
i = write_marked(temp, TRUE, FALSE);
|
i = write_marked(temp, temp_file, TRUE, FALSE);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
i = write_file(temp, TRUE, FALSE, FALSE);
|
i = write_file(temp, temp_file, TRUE, FALSE, FALSE);
|
||||||
|
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
statusbar(_("Error writing temp file: %s"), strerror(errno));
|
statusbar(_("Error writing temp file: %s"), strerror(errno));
|
||||||
|
@ -3368,7 +3369,7 @@ void do_exit(void)
|
||||||
dump_buffer(fileage);
|
dump_buffer(fileage);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
|
if (i == 0 || (i == 1 && do_writeout(TRUE) == 0)) {
|
||||||
#ifdef ENABLE_MULTIBUFFER
|
#ifdef ENABLE_MULTIBUFFER
|
||||||
/* Exit only if there are no more open file buffers. */
|
/* Exit only if there are no more open file buffers. */
|
||||||
if (!close_open_file())
|
if (!close_open_file())
|
||||||
|
|
|
@ -280,7 +280,7 @@ char *get_full_path(const char *origpath);
|
||||||
#endif
|
#endif
|
||||||
#ifndef DISABLE_SPELLER
|
#ifndef DISABLE_SPELLER
|
||||||
char *check_writable_directory(const char *path);
|
char *check_writable_directory(const char *path);
|
||||||
char *safe_tempnam(void);
|
char *safe_tempfile(FILE **f);
|
||||||
#endif
|
#endif
|
||||||
#ifndef DISABLE_OPERATINGDIR
|
#ifndef DISABLE_OPERATINGDIR
|
||||||
void init_operating_dir(void);
|
void init_operating_dir(void);
|
||||||
|
@ -290,10 +290,10 @@ bool check_operating_dir(const char *currpath, bool allow_tabcomp);
|
||||||
void init_backup_dir(void);
|
void init_backup_dir(void);
|
||||||
#endif
|
#endif
|
||||||
int copy_file(FILE *inn, FILE *out);
|
int copy_file(FILE *inn, FILE *out);
|
||||||
int write_file(const char *name, bool tmp, int append, bool
|
int write_file(const char *name, FILE *f_open, bool tmp, int append,
|
||||||
nonamechange);
|
bool nonamechange);
|
||||||
#ifndef NANO_SMALL
|
#ifndef NANO_SMALL
|
||||||
int write_marked(const char *name, bool tmp, int append);
|
int write_marked(const char *name, FILE *f_open, bool tmp, int append);
|
||||||
#endif
|
#endif
|
||||||
int do_writeout(bool exiting);
|
int do_writeout(bool exiting);
|
||||||
void do_writeout_void(void);
|
void do_writeout_void(void);
|
||||||
|
|
Loading…
Reference in New Issue