From 967942c7425ddf0f3daedd769fa0490ed88317d8 Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Mon, 26 Jan 2015 15:10:26 +0100 Subject: [PATCH] Resolves: #1183320 - fix the file locking feature of nano --- nano-2.3.6-lockfile.patch | 338 ++++++++++++++++++++++++++++++++++++++ nano.spec | 9 +- 2 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 nano-2.3.6-lockfile.patch diff --git a/nano-2.3.6-lockfile.patch b/nano-2.3.6-lockfile.patch new file mode 100644 index 0000000..7221613 --- /dev/null +++ b/nano-2.3.6-lockfile.patch @@ -0,0 +1,338 @@ +From 131d4b0988f319736bb36760cee300934bf9bc12 Mon Sep 17 00:00:00 2001 +From: astyanax +Date: Wed, 14 Jan 2015 02:36:30 +0000 +Subject: [PATCH 1/3] 2015-01-13 Chris Allegretta * + src/files.c (open_buffer): Check here for locking and properly handle + choosing to not open a file when locked instead of in open_file(). Fixes + Savannah bug 42373 reported by Benno Schulenberg + +git-svn-id: file:///home/kdudka/git/nano-svn/nano@5104 ac9c2fa3-95a5-41e5-9206-2167041ecc6c +--- + src/files.c | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/src/files.c b/src/files.c +index a195e6f..e027d69 100644 +--- a/src/files.c ++++ b/src/files.c +@@ -355,9 +355,25 @@ void open_buffer(const char *filename, bool undoable) + + /* If we're loading into a new buffer, add a new entry to + * openfile. */ +- if (new_buffer) ++ if (new_buffer) { + make_new_buffer(); + ++#ifndef NANO_TINY ++ if (ISSET(LOCKING) && filename[0] != '\0') { ++ int lockstatus = do_lockfile(filename); ++ if (lockstatus < 0) { ++ if (openfile->next) { ++ close_buffer(); ++ statusbar(_("Cancelled")); ++ return; ++ } else ++ filename = ""; ++ } ++ } ++#endif ++ } ++ ++ + /* If the filename isn't blank, and we are not in NOREAD_MODE, + * open the file. Otherwise, treat it as a new file. */ + rc = (filename[0] != '\0' && !ISSET(NOREAD_MODE)) ? +@@ -920,16 +936,6 @@ int open_file(const char *filename, bool newfie, FILE **f) + full_filename = mallocstrcpy(NULL, filename); + + +-#ifndef NANO_TINY +- if (ISSET(LOCKING)) { +- int lockstatus = do_lockfile(full_filename); +- if (lockstatus < 0) +- return -1; +- else if (lockstatus == 0) +- quiet = 1; +- } +-#endif +- + if (stat(full_filename, &fileinfo) == -1) { + /* Well, maybe we can open the file even if the OS says it's + * not there. */ +-- +2.1.0 + + +From f47060c02f57279445281e9f23079f2bdccdca3a Mon Sep 17 00:00:00 2001 +From: astyanax +Date: Tue, 20 Jan 2015 06:15:34 +0000 +Subject: [PATCH 2/3] Take 2 at file locking fixes. New args to close_buffer() + and switch_to_prevnext_buffer() to support message passthrough when trying to + lock files using multibuffer. + +git-svn-id: file:///home/kdudka/git/nano-svn/nano@5105 ac9c2fa3-95a5-41e5-9206-2167041ecc6c +--- + src/files.c | 66 ++++++++++++++++++++++++++++++++++++------------------------- + src/nano.c | 2 +- + src/proto.h | 6 +++--- + 3 files changed, 43 insertions(+), 31 deletions(-) + +diff --git a/src/files.c b/src/files.c +index e027d69..faa2e62 100644 +--- a/src/files.c ++++ b/src/files.c +@@ -126,6 +126,7 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi + pid_t mypid; + uid_t myuid; + struct passwd *mypwuid; ++ struct stat fileinfo; + char *lockdata = charalloc(1024); + char myhostname[32]; + ssize_t lockdatalen = 1024; +@@ -145,8 +146,10 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi + return -1; + } + +- if (delete_lockfile(lockfilename) < 0) +- return -1; ++ /* Check if the lock exists before we try to delete it...*/ ++ if (stat(lockfilename, &fileinfo) != -1) ++ if (delete_lockfile(lockfilename) < 0) ++ return -1; + + if (ISSET(INSECURE_BACKUP)) + cflags = O_WRONLY | O_CREAT | O_APPEND; +@@ -156,11 +159,13 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi + fd = open(lockfilename, cflags, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + +- /* Maybe we just don't have write access. Don't stop us from +- * opening the file at all, just don't set the lock_filename and +- * return success. */ +- if (fd < 0 && errno == EACCES) +- return 1; ++ /* Maybe we just don't have write access. Print an error message ++ and continue. */ ++ if (fd < 0) { ++ statusbar(_("Error writing lock file %s: %s"), lockfilename, ++ strerror(errno)); ++ return 0; ++ } + + /* Now we've got a safe file stream. If the previous open() call + * failed, this will return NULL. */ +@@ -229,8 +234,8 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi + int delete_lockfile(const char *lockfilename) + { + if (unlink(lockfilename) < 0 && errno != ENOENT) { +- statusbar(_("Error deleting lock file %s: %s"), lockfilename, +- strerror(errno)); ++ statusbar(_("Error deleting lock file %s: %s"), lockfilename, ++ strerror(errno)); + return -1; + } + return 1; +@@ -332,6 +337,7 @@ void stat_if_needed(const char *filename, struct stat **pstat) + * necessary, and then open and read the file, if applicable. */ + void open_buffer(const char *filename, bool undoable) + { ++ bool quiet = FALSE; + bool new_buffer = (openfile == NULL + #ifndef DISABLE_MULTIBUFFER + || ISSET(MULTIBUFFER) +@@ -362,12 +368,14 @@ void open_buffer(const char *filename, bool undoable) + if (ISSET(LOCKING) && filename[0] != '\0') { + int lockstatus = do_lockfile(filename); + if (lockstatus < 0) { ++#ifndef DISABLE_MULTIBUFFER + if (openfile->next) { +- close_buffer(); +- statusbar(_("Cancelled")); ++ close_buffer(TRUE); + return; +- } else +- filename = ""; ++ } ++#endif ++ } else if (lockstatus == 0) { ++ quiet = TRUE; + } + } + #endif +@@ -377,7 +385,7 @@ void open_buffer(const char *filename, bool undoable) + /* If the filename isn't blank, and we are not in NOREAD_MODE, + * open the file. Otherwise, treat it as a new file. */ + rc = (filename[0] != '\0' && !ISSET(NOREAD_MODE)) ? +- open_file(filename, new_buffer, &f) : -2; ++ open_file(filename, new_buffer, quiet, &f) : -2; + + /* If we have a file, and we're loading into a new buffer, update + * the filename. */ +@@ -425,7 +433,7 @@ void replace_buffer(const char *filename) + + /* If the filename isn't blank, open the file. Otherwise, treat it + * as a new file. */ +- rc = (filename[0] != '\0') ? open_file(filename, TRUE, &f) : -2; ++ rc = (filename[0] != '\0') ? open_file(filename, TRUE, FALSE, &f) : -2; + + /* Reinitialize the text of the current buffer. */ + free_filestruct(openfile->fileage); +@@ -461,14 +469,15 @@ void display_buffer(void) + #ifndef DISABLE_MULTIBUFFER + /* Switch to the next file buffer if next_buf is TRUE. Otherwise, + * switch to the previous file buffer. */ +-void switch_to_prevnext_buffer(bool next_buf) ++void switch_to_prevnext_buffer(bool next_buf, bool quiet) + { + assert(openfile != NULL); + + /* If only one file buffer is open, indicate it on the statusbar and + * get out. */ + if (openfile == openfile->next) { +- statusbar(_("No more open file buffers")); ++ if (quiet == FALSE) ++ statusbar(_("No more open file buffers")); + return; + } + +@@ -484,9 +493,10 @@ void switch_to_prevnext_buffer(bool next_buf) + display_buffer(); + + /* Indicate the switch on the statusbar. */ +- statusbar(_("Switched to %s"), +- ((openfile->filename[0] == '\0') ? _("New Buffer") : +- openfile->filename)); ++ if (quiet == FALSE) ++ statusbar(_("Switched to %s"), ++ ((openfile->filename[0] == '\0') ? _("New Buffer") : ++ openfile->filename)); + + #ifdef DEBUG + dump_filestruct(openfile->current); +@@ -497,19 +507,21 @@ void switch_to_prevnext_buffer(bool next_buf) + /* Switch to the previous entry in the openfile filebuffer. */ + void switch_to_prev_buffer_void(void) + { +- switch_to_prevnext_buffer(FALSE); ++ switch_to_prevnext_buffer(FALSE, FALSE); + } + + /* Switch to the next entry in the openfile filebuffer. */ + void switch_to_next_buffer_void(void) + { +- switch_to_prevnext_buffer(TRUE); ++ switch_to_prevnext_buffer(TRUE, FALSE); + } + + /* Delete an entry from the openfile filebuffer, and switch to the one + * after it. Return TRUE on success, or FALSE if there are no more open +- * file buffers. */ +-bool close_buffer(void) ++ * file buffers. ++ * quiet - should we print messages switching bufers ++ */ ++bool close_buffer(bool quiet) + { + assert(openfile != NULL); + +@@ -522,7 +534,7 @@ bool close_buffer(void) + #endif + + /* Switch to the next file buffer. */ +- switch_to_next_buffer_void(); ++ switch_to_prevnext_buffer(TRUE, quiet); + + /* Close the file buffer we had open before. */ + unlink_opennode(openfile->prev); +@@ -918,10 +930,10 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable, bool checkw + * Return -2 if we say "New File", -1 if the file isn't opened, and the + * fd opened otherwise. The file might still have an error while reading + * with a 0 return value. *f is set to the opened file. */ +-int open_file(const char *filename, bool newfie, FILE **f) ++int open_file(const char *filename, bool newfie, bool quiet, FILE **f) + { + struct stat fileinfo, fileinfo2; +- int fd, quiet = 0; ++ int fd; + char *full_filename; + + assert(filename != NULL && f != NULL); +diff --git a/src/nano.c b/src/nano.c +index 6c655bc..9635c24 100644 +--- a/src/nano.c ++++ b/src/nano.c +@@ -1152,7 +1152,7 @@ void do_exit(void) + + #ifndef DISABLE_MULTIBUFFER + /* Exit only if there are no more open file buffers. */ +- if (!close_buffer()) ++ if (!close_buffer(FALSE)) + #endif + finish(); + /* If the user canceled, we go on. */ +diff --git a/src/proto.h b/src/proto.h +index 20f1fdb..579e6cf 100644 +--- a/src/proto.h ++++ b/src/proto.h +@@ -283,15 +283,15 @@ void replace_buffer(const char *filename); + #endif + void display_buffer(void); + #ifndef DISABLE_MULTIBUFFER +-void switch_to_prevnext_buffer(bool next); ++void switch_to_prevnext_buffer(bool next, bool quiet); + void switch_to_prev_buffer_void(void); + void switch_to_next_buffer_void(void); +-bool close_buffer(void); ++bool close_buffer(bool quiet); + #endif + filestruct *read_line(char *buf, filestruct *prevnode, bool + *first_line_ins, size_t buf_len); + void read_file(FILE *f, int fd, const char *filename, bool undoable, bool checkwritable); +-int open_file(const char *filename, bool newfie, FILE **f); ++int open_file(const char *filename, bool newfie, bool quiet, FILE **f); + char *get_next_filename(const char *name, const char *suffix); + void do_insertfile( + #ifndef NANO_TINY +-- +2.1.0 + + +From 7fa511ffbd45975e0638ea3497b49081f99c4bc9 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 26 Jan 2015 14:55:39 +0100 +Subject: [PATCH 3/3] avoid writing uninitialized bytes to the lock file + +The call to null_at() would not initialize the buffer: + +Syscall param write(buf) points to uninitialised byte(s) + at 0x3EA76F0EB0: __write_nocancel (syscall-template.S:81) + by 0x3EA767949C: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1302) + by 0x3EA767A948: new_do_write (fileops.c:537) + by 0x3EA767A948: _IO_do_write@@GLIBC_2.2.5 (fileops.c:510) + by 0x3EA767A22F: _IO_file_close_it@@GLIBC_2.2.5 (fileops.c:166) + by 0x3EA766E2C1: fclose@@GLIBC_2.2.5 (iofclose.c:59) + by 0x40814C: write_lockfile (files.c:221) + by 0x40847C: do_lockfile (files.c:314) + by 0x40BC5E: open_buffer (files.c:351) + by 0x4041D7: main (nano.c:2761) + Address 0x4c1900c is not stack'd, malloc'd or (recently) free'd +--- + src/files.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/files.c b/src/files.c +index faa2e62..1d0f0a8 100644 +--- a/src/files.c ++++ b/src/files.c +@@ -195,7 +195,7 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi + * our lockfile' message in here... + * + * This is likely very wrong, so this is a WIP. */ +- null_at(&lockdata, lockdatalen); ++ memset(lockdata, 0, lockdatalen); + lockdata[0] = 0x62; + lockdata[1] = 0x30; + lockdata[24] = mypid % 256; +-- +2.1.0 + diff --git a/nano.spec b/nano.spec index d3ce3ce..722036e 100644 --- a/nano.spec +++ b/nano.spec @@ -1,7 +1,7 @@ Summary: A small text editor Name: nano Version: 2.3.6 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv3+ Group: Applications/Editors URL: http://www.nano-editor.org @@ -15,6 +15,9 @@ Patch1: 0001-check-stat-s-result-and-avoid-calling-stat-on-a-NULL.patch # http://lists.gnu.org/archive/html/nano-devel/2010-08/msg00005.html Patch2: 0002-use-futimens-if-available-instead-of-utime.patch +# fix the file locking feature of nano (#1183320) +Patch3: nano-2.3.6-lockfile.patch + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: file-devel BuildRequires: gettext-devel @@ -34,6 +37,7 @@ GNU nano is a small and friendly text editor. %patch0 -p1 %patch1 -p1 %patch2 -p1 +%patch3 -p1 for f in doc/man/fr/{nano.1,nanorc.5,rnano.1} ; do iconv -f iso-8859-1 -t utf-8 -o $f.tmp $f && mv $f.tmp $f @@ -89,6 +93,9 @@ exit 0 %{_datadir}/nano %changelog +* Mon Jan 26 2015 Kamil Dudka - 2.3.6-5 +- fix the file locking feature of nano (#1183320) + * Mon Jan 05 2015 Kamil Dudka - 2.3.6-4 - drop BR for autoconf, which is no longer needed