Bug Summary

File:src/usr.bin/vi/build/../common/exf.c
Warning:line 425, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name exf.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/vi/build/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/vi/build -I /usr/src/usr.bin/vi/build/../include -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/vi/build/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/vi/build/../common/exf.c
1/* $OpenBSD: exf.c,v 1.48 2021/10/25 14:17:24 dv Exp $ */
2
3/*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
8 *
9 * See the LICENSE file for redistribution information.
10 */
11
12#include "config.h"
13
14#include <sys/queue.h>
15#include <sys/stat.h>
16#include <sys/time.h>
17
18/*
19 * We include <sys/file.h>, because the flock(2) and open(2) #defines
20 * were found there on historical systems. We also include <fcntl.h>
21 * because the open(2) #defines are found there on newer systems.
22 */
23#include <sys/file.h>
24
25#include <bitstring.h>
26#include <dirent.h>
27#include <errno(*__errno()).h>
28#include <fcntl.h>
29#include <limits.h>
30#include <signal.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <time.h>
35#include <unistd.h>
36
37#include "common.h"
38
39static int file_backup(SCR *, char *, char *);
40static void file_cinit(SCR *);
41static void file_comment(SCR *);
42static int file_spath(SCR *, FREF *, struct stat *, int *);
43
44/*
45 * file_add --
46 * Insert a file name into the FREF list, if it doesn't already
47 * appear in it.
48 *
49 * !!!
50 * The "if it doesn't already appear" changes vi's semantics slightly. If
51 * you do a "vi foo bar", and then execute "next bar baz", the edit of bar
52 * will reflect the line/column of the previous edit session. Historic nvi
53 * did not do this. The change is a logical extension of the change where
54 * vi now remembers the last location in any file that it has ever edited,
55 * not just the previously edited file.
56 *
57 * PUBLIC: FREF *file_add(SCR *, CHAR_T *);
58 */
59FREF *
60file_add(SCR *sp, CHAR_T *name)
61{
62 GS *gp;
63 FREF *frp, *tfrp;
64
65 /*
66 * Return it if it already exists. Note that we test against the
67 * user's name, whatever that happens to be, including if it's a
68 * temporary file.
69 *
70 * If the user added a file but was unable to initialize it, there
71 * can be file list entries where the name field is NULL. Discard
72 * them the next time we see them.
73 */
74 gp = sp->gp;
75 if (name != NULL((void *)0))
76 TAILQ_FOREACH_SAFE(frp, &gp->frefq, q, tfrp)for ((frp) = ((&gp->frefq)->tqh_first); (frp) != ((
void *)0) && ((tfrp) = ((frp)->q.tqe_next), 1); (frp
) = (tfrp))
{
77 if (frp->name == NULL((void *)0)) {
78 TAILQ_REMOVE(&gp->frefq, frp, q)do { if (((frp)->q.tqe_next) != ((void *)0)) (frp)->q.tqe_next
->q.tqe_prev = (frp)->q.tqe_prev; else (&gp->frefq
)->tqh_last = (frp)->q.tqe_prev; *(frp)->q.tqe_prev =
(frp)->q.tqe_next; ; ; } while (0)
;
79 free(frp->name);
80 free(frp);
81 continue;
82 }
83 if (!strcmp(frp->name, name))
84 return (frp);
85 }
86
87 /* Allocate and initialize the FREF structure. */
88 CALLOC(sp, frp, 1, sizeof(FREF)){ if (((frp) = calloc((1), (sizeof(FREF)))) == ((void *)0)) msgq
((sp), M_SYSERR, ((void *)0)); }
;
89 if (frp == NULL((void *)0))
90 return (NULL((void *)0));
91
92 /*
93 * If no file name specified, or if the file name is a request
94 * for something temporary, file_init() will allocate the file
95 * name. Temporary files are always ignored.
96 */
97 if (name != NULL((void *)0) && strcmp(name, TEMPORARY_FILE_STRING"/tmp") &&
98 (frp->name = strdup(name)) == NULL((void *)0)) {
99 free(frp);
100 msgq(sp, M_SYSERR, NULL((void *)0));
101 return (NULL((void *)0));
102 }
103
104 /* Append into the chain of file names. */
105 TAILQ_INSERT_TAIL(&gp->frefq, frp, q)do { (frp)->q.tqe_next = ((void *)0); (frp)->q.tqe_prev
= (&gp->frefq)->tqh_last; *(&gp->frefq)->
tqh_last = (frp); (&gp->frefq)->tqh_last = &(frp
)->q.tqe_next; } while (0)
;
106
107 return (frp);
108}
109
110/*
111 * file_init --
112 * Start editing a file, based on the FREF structure. If successsful,
113 * let go of any previous file. Don't release the previous file until
114 * absolutely sure we have the new one.
115 *
116 * PUBLIC: int file_init(SCR *, FREF *, char *, int);
117 */
118int
119file_init(SCR *sp, FREF *frp, char *rcv_name, int flags)
120{
121 EXF *ep;
122 RECNOINFO oinfo;
123 struct stat sb;
124 size_t psize;
125 int fd, exists, open_err, readonly;
126 char *oname, tname[] = "/tmp/vi.XXXXXXXXXX";
127
128 open_err = readonly = 0;
129
130 /*
131 * If the file is a recovery file, let the recovery code handle it.
132 * Clear the FR_RECOVER flag first -- the recovery code does set up,
133 * and then calls us! If the recovery call fails, it's probably
134 * because the named file doesn't exist. So, move boldly forward,
135 * presuming that there's an error message the user will get to see.
136 */
137 if (F_ISSET(frp, FR_RECOVER)(((frp)->flags) & ((0x0020)))) {
1
Assuming the condition is false
2
Taking false branch
138 F_CLR(frp, FR_RECOVER)(((frp)->flags) &= ~((0x0020)));
139 if (rcv_read(sp, frp) == 0)
140 return (0); /* successful recovery */
141 }
142
143 /*
144 * Required FRP initialization; the only flag we keep is the
145 * cursor information.
146 */
147 F_CLR(frp, ~FR_CURSORSET)(((frp)->flags) &= ~((~0x0001)));
148
149 /*
150 * Required EXF initialization:
151 * Flush the line caches.
152 * Default recover mail file fd to -1.
153 * Set initial EXF flag bits.
154 */
155 CALLOC_RET(sp, ep, 1, sizeof(EXF)){ if (((ep) = calloc((1), (sizeof(EXF)))) == ((void *)0)) { msgq
((sp), M_SYSERR, ((void *)0)); return (1); } }
;
3
Assuming the condition is false
4
Taking false branch
156 ep->c_lno = ep->c_nlines = OOBLNO0;
157 ep->rcv_fd = ep->fcntl_fd = -1;
158 F_SET(ep, F_FIRSTMODIFY)(((ep)->flags) |= ((0x002)));
159
160 /*
161 * Scan the user's path to find the file that we're going to
162 * try and open.
163 */
164 if (file_spath(sp, frp, &sb, &exists)) {
5
Taking false branch
165 free(ep);
166 return (1);
167 }
168
169 /*
170 * If no name or backing file, for whatever reason, create a backing
171 * temporary file, saving the temp file name so we can later unlink
172 * it. If the user never named this file, copy the temporary file name
173 * to the real name (we display that until the user renames it).
174 */
175 oname = frp->name;
176
177 /*
178 * User is editing a named file that doesn't exist yet other than as a
179 * temporary file.
180 */
181 if (!exists
5.1
'exists' is 0
&& oname
5.2
'oname' is equal to NULL
!= NULL((void *)0) && frp->tname != NULL((void *)0)) {
182 free(ep);
183 return (1);
184 }
185
186 if (LF_ISSET(FS_OPENERR)((flags) & ((0x008))) || oname == NULL((void *)0) || !exists) {
6
Assuming the condition is true
187 /*
188 * Don't try to create a temporary support file twice.
189 */
190 if (frp->tname != NULL((void *)0))
7
Assuming field 'tname' is equal to NULL
8
Taking false branch
191 goto err;
192 fd = mkstemp(tname);
193 if (fd == -1 || fstat(fd, &sb) == -1 ||
9
Assuming the condition is false
10
Assuming the condition is false
12
Taking false branch
194 fchmod(fd, S_IRUSR0000400 | S_IWUSR0000200) == -1) {
11
Assuming the condition is false
195 msgq(sp, M_SYSERR,
196 "Unable to create temporary file");
197 if (fd != -1) {
198 close(fd);
199 (void)unlink(tname);
200 }
201 goto err;
202 }
203 (void)close(fd);
204
205 if (frp->name
12.1
Field 'name' is equal to NULL
== NULL((void *)0))
13
Taking true branch
206 F_SET(frp, FR_TMPFILE)(((frp)->flags) |= ((0x0080)));
207 if ((frp->tname = strdup(tname)) == NULL((void *)0) ||
14
Memory is allocated
15
Assuming the condition is false
17
Taking true branch
208 (frp->name
15.1
Field 'name' is equal to NULL
== NULL((void *)0) && (frp->name = strdup(tname)) == NULL((void *)0))) {
16
Assuming the condition is true
209 free(frp->tname);
18
Memory is released
210 msgq(sp, M_SYSERR, NULL((void *)0));
211 (void)unlink(tname);
212 goto err;
19
Control jumps to line 422
213 }
214 oname = frp->tname;
215 psize = 1024;
216 if (!LF_ISSET(FS_OPENERR)((flags) & ((0x008))))
217 F_SET(frp, FR_NEWFILE)(((frp)->flags) |= ((0x0010)));
218 } else {
219 /*
220 * XXX
221 * A seat of the pants calculation: try to keep the file in
222 * 15 pages or less. Don't use a page size larger than 10K
223 * (vi should have good locality) or smaller than 1K.
224 */
225 psize = ((sb.st_size / 15) + 1023) / 1024;
226 if (psize > 10)
227 psize = 10;
228 if (psize == 0)
229 psize = 1;
230 psize *= 1024;
231
232 if (!S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000))
233 msgq_str(sp, M_ERR, oname,
234 "Warning: %s is not a regular file");
235 }
236
237 /* Save device, inode and modification time. */
238 F_SET(ep, F_DEVSET)(((ep)->flags) |= ((0x001)));
239 ep->mdev = sb.st_dev;
240 ep->minode = sb.st_ino;
241
242 ep->mtim = sb.st_mtim;
243
244 /* Set up recovery. */
245 memset(&oinfo, 0, sizeof(RECNOINFO));
246 oinfo.bval = '\n'; /* Always set. */
247 oinfo.psize = psize;
248 oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT)(((sp->gp)->flags) & ((0x0040))) ? R_SNAPSHOT0x04 : 0;
249 if (rcv_name == NULL((void *)0)) {
250 if (!rcv_tmp(sp, ep, frp->name))
251 oinfo.bfname = ep->rcv_path;
252 } else {
253 if ((ep->rcv_path = strdup(rcv_name)) == NULL((void *)0)) {
254 msgq(sp, M_SYSERR, NULL((void *)0));
255 goto err;
256 }
257 oinfo.bfname = ep->rcv_path;
258 F_SET(ep, F_MODIFIED)(((ep)->flags) |= ((0x004)));
259 }
260
261 /* Open a db structure. */
262 if ((ep->db = dbopen(rcv_name == NULL((void *)0) ? oname : NULL((void *)0),
263 O_NONBLOCK0x0004 | O_RDONLY0x0000,
264 S_IRUSR0000400 | S_IWUSR0000200 | S_IRGRP0000040 | S_IWGRP0000020 | S_IROTH0000004 | S_IWOTH0000002,
265 DB_RECNO, &oinfo)) == NULL((void *)0)) {
266 msgq_str(sp,
267 M_SYSERR, rcv_name == NULL((void *)0) ? oname : rcv_name, "%s");
268 /*
269 * !!!
270 * Historically, vi permitted users to edit files that couldn't
271 * be read. This isn't useful for single files from a command
272 * line, but it's quite useful for "vi *.c", since you can skip
273 * past files that you can't read.
274 */
275 open_err = 1;
276 goto oerr;
277 }
278
279 /*
280 * Do the remaining things that can cause failure of the new file,
281 * mark and logging initialization.
282 */
283 if (mark_init(sp, ep) || log_init(sp, ep))
284 goto err;
285
286 /*
287 * Set the alternate file name to be the file we're discarding.
288 *
289 * !!!
290 * Temporary files can't become alternate files, so there's no file
291 * name. This matches historical practice, although it could only
292 * happen in historical vi as the result of the initial command, i.e.
293 * if vi was executed without a file name.
294 */
295 if (LF_ISSET(FS_SETALT)((flags) & ((0x020))))
296 set_alt_name(sp, sp->frp == NULL((void *)0) ||
297 F_ISSET(sp->frp, FR_TMPFILE)(((sp->frp)->flags) & ((0x0080))) ? NULL((void *)0) : sp->frp->name);
298
299 /*
300 * Close the previous file; if that fails, close the new one and run
301 * for the border.
302 *
303 * !!!
304 * There's a nasty special case. If the user edits a temporary file,
305 * and then does an ":e! %", we need to re-initialize the backing
306 * file, but we can't change the name. (It's worse -- we're dealing
307 * with *names* here, we can't even detect that it happened.) Set a
308 * flag so that the file_end routine ignores the backing information
309 * of the old file if it happens to be the same as the new one.
310 *
311 * !!!
312 * Side-effect: after the call to file_end(), sp->frp may be NULL.
313 */
314 if (sp->ep != NULL((void *)0)) {
315 F_SET(frp, FR_DONTDELETE)(((frp)->flags) |= ((0x0002)));
316 if (file_end(sp, NULL((void *)0), LF_ISSET(FS_FORCE)((flags) & ((0x004))))) {
317 (void)file_end(sp, ep, 1);
318 goto err;
319 }
320 F_CLR(frp, FR_DONTDELETE)(((frp)->flags) &= ~((0x0002)));
321 }
322
323 /*
324 * Lock the file; if it's a recovery file, it should already be
325 * locked. Note, we acquire the lock after the previous file
326 * has been ended, so that we don't get an "already locked" error
327 * for ":edit!".
328 *
329 * XXX
330 * While the user can't interrupt us between the open and here,
331 * there's a race between the dbopen() and the lock. Not much
332 * we can do about it.
333 *
334 * XXX
335 * We don't make a big deal of not being able to lock the file. As
336 * locking rarely works over NFS, and often fails if the file was
337 * mmap(2)'d, it's far too common to do anything like print an error
338 * message, let alone make the file readonly. At some future time,
339 * when locking is a little more reliable, this should change to be
340 * an error.
341 */
342 if (rcv_name == NULL((void *)0) && !O_ISSET(sp, O_READONLY)((((&(((sp)))->opts[(((O_READONLY)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_READONLY
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_READONLY))
)].o_cur.val)
)
343 switch (file_lock(sp, oname,
344 &ep->fcntl_fd, ep->db->fd(ep->db), 0)) {
345 case LOCK_FAILED:
346 F_SET(frp, FR_UNLOCKED)(((frp)->flags) |= ((0x0100)));
347 break;
348 case LOCK_UNAVAIL:
349 readonly = 1;
350 msgq_str(sp, M_INFO, oname,
351 "%s already locked, session is read-only");
352 break;
353 case LOCK_SUCCESS:
354 break;
355 }
356
357 /*
358 * Historically, the readonly edit option was set per edit buffer in
359 * vi, unless the -R command-line option was specified or the program
360 * was executed as "view". (Well, to be truthful, if the letter 'w'
361 * occurred anywhere in the program name, but let's not get into that.)
362 * So, the persistent readonly state has to be stored in the screen
363 * structure, and the edit option value toggles with the contents of
364 * the edit buffer. If the persistent readonly flag is set, set the
365 * readonly edit option.
366 *
367 * Otherwise, try and figure out if a file is readonly. This is a
368 * dangerous thing to do. The kernel is the only arbiter of whether
369 * or not a file is writeable, and the best that a user program can
370 * do is guess. Obvious loopholes are files that are on a file system
371 * mounted readonly (access catches this one on a few systems), or
372 * alternate protection mechanisms, ACL's for example, that we can't
373 * portably check. Lots of fun, and only here because users whined.
374 *
375 * !!!
376 * Historic vi displayed the readonly message if none of the file
377 * write bits were set, or if an an access(2) call on the path
378 * failed. This seems reasonable. If the file is mode 444, root
379 * users may want to know that the owner of the file did not expect
380 * it to be written.
381 *
382 * Historic vi set the readonly bit if no write bits were set for
383 * a file, even if the access call would have succeeded. This makes
384 * the superuser force the write even when vi expects that it will
385 * succeed. I'm less supportive of this semantic, but it's historic
386 * practice and the conservative approach to vi'ing files as root.
387 *
388 * It would be nice if there was some way to update this when the user
389 * does a "^Z; chmod ...". The problem is that we'd first have to
390 * distinguish between readonly bits set because of file permissions
391 * and those set for other reasons. That's not too hard, but deciding
392 * when to reevaluate the permissions is trickier. An alternative
393 * might be to turn off the readonly bit if the user forces a write
394 * and it succeeds.
395 *
396 * XXX
397 * Access(2) doesn't consider the effective uid/gid values. This
398 * probably isn't a problem for vi when it's running standalone.
399 */
400 if (readonly || F_ISSET(sp, SC_READONLY)(((sp)->flags) & ((0x00200000))) ||
401 (!F_ISSET(frp, FR_NEWFILE)(((frp)->flags) & ((0x0010))) &&
402 (!(sb.st_mode & (S_IWUSR0000200 | S_IWGRP0000020 | S_IWOTH0000002)) ||
403 access(frp->name, W_OK0x02))))
404 O_SET(sp, O_READONLY)o_set((sp), (O_READONLY), 0, ((void *)0), 1);
405 else
406 O_CLR(sp, O_READONLY)o_set((sp), (O_READONLY), 0, ((void *)0), 0);
407
408 /* Switch... */
409 ++ep->refcnt;
410 sp->ep = ep;
411 sp->frp = frp;
412
413 /* Set the initial cursor position, queue initial command. */
414 file_cinit(sp);
415
416 /* Redraw the screen from scratch, schedule a welcome message. */
417 F_SET(sp, SC_SCR_REFORMAT | SC_STATUS)(((sp)->flags) |= ((0x00000020 | 0x02000000)));
418
419 return (0);
420
421err:
422 free(frp->name);
423 frp->name = NULL((void *)0);
424 if (frp->tname
19.1
Field 'tname' is not equal to NULL
!= NULL((void *)0)) {
20
Taking true branch
425 (void)unlink(frp->tname);
21
Use of memory after it is freed
426 free(frp->tname);
427 frp->tname = NULL((void *)0);
428 }
429
430oerr: if (F_ISSET(ep, F_RCV_ON)(((ep)->flags) & ((0x040))))
431 (void)unlink(ep->rcv_path);
432 free(ep->rcv_path);
433 ep->rcv_path = NULL((void *)0);
434 if (ep->db != NULL((void *)0))
435 (void)ep->db->close(ep->db);
436 free(ep);
437
438 return (open_err ?
439 file_init(sp, frp, rcv_name, flags | FS_OPENERR0x008) : 1);
440}
441
442/*
443 * file_spath --
444 * Scan the user's path to find the file that we're going to
445 * try and open.
446 */
447static int
448file_spath(SCR *sp, FREF *frp, struct stat *sbp, int *existsp)
449{
450 CHAR_T savech;
451 size_t len;
452 int found;
453 char *name, *p, *t, path[PATH_MAX1024];
454
455 /*
456 * If the name is NULL or an explicit reference (i.e., the first
457 * component is . or ..) ignore the O_PATH option.
458 */
459 name = frp->name;
460 if (name == NULL((void *)0)) {
461 *existsp = 0;
462 return (0);
463 }
464 if (name[0] == '/' || (name[0] == '.' &&
465 (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) {
466 *existsp = !stat(name, sbp);
467 return (0);
468 }
469
470 /* Try . */
471 if (!stat(name, sbp)) {
472 *existsp = 1;
473 return (0);
474 }
475
476 /* Try the O_PATH option values. */
477 for (found = 0, p = t = O_STR(sp, O_PATH)((((&((sp))->opts[((O_PATH))])->flags) & ((0x01
))) ? ((sp))->gp->opts[((sp))->opts[((O_PATH))].o_cur
.val].o_cur.str : ((sp))->opts[((O_PATH))].o_cur.str)
;; ++p)
478 if (*p == ':' || *p == '\0') {
479 if (t < p - 1) {
480 savech = *p;
481 *p = '\0';
482 len = snprintf(path,
483 sizeof(path), "%s/%s", t, name);
484 if (len >= sizeof(path))
485 len = sizeof(path) - 1;
486 *p = savech;
487 if (!stat(path, sbp)) {
488 found = 1;
489 break;
490 }
491 }
492 t = p + 1;
493 if (*p == '\0')
494 break;
495 }
496
497 /* If we found it, build a new pathname and discard the old one. */
498 if (found) {
499 MALLOC_RET(sp, p, len + 1){ if (((p) = malloc(len + 1)) == ((void *)0)) { msgq((sp), M_SYSERR
, ((void *)0)); return (1); } }
;
500 memcpy(p, path, len + 1);
501 free(frp->name);
502 frp->name = p;
503 }
504 *existsp = found;
505 return (0);
506}
507
508/*
509 * file_cinit --
510 * Set up the initial cursor position.
511 */
512static void
513file_cinit(SCR *sp)
514{
515 GS *gp;
516 MARK m;
517 size_t len;
518 int nb;
519
520 /* Set some basic defaults. */
521 sp->lno = 1;
522 sp->cno = 0;
523
524 /*
525 * Historically, initial commands (the -c option) weren't executed
526 * until a file was loaded, e.g. "vi +10 nofile", followed by an
527 * :edit or :tag command, would execute the +10 on the file loaded
528 * by the subsequent command, (assuming that it existed). This
529 * applied as well to files loaded using the tag commands, and we
530 * follow that historic practice. Also, all initial commands were
531 * ex commands and were always executed on the last line of the file.
532 *
533 * Otherwise, if no initial command for this file:
534 * If in ex mode, move to the last line, first nonblank character.
535 * If the file has previously been edited, move to the last known
536 * position, and check it for validity.
537 * Otherwise, move to the first line, first nonblank.
538 *
539 * This gets called by the file init code, because we may be in a
540 * file of ex commands and we want to execute them from the right
541 * location in the file.
542 */
543 nb = 0;
544 gp = sp->gp;
545 if (gp->c_option != NULL((void *)0) && !F_ISSET(sp->frp, FR_NEWFILE)(((sp->frp)->flags) & ((0x0010)))) {
546 if (db_last(sp, &sp->lno))
547 return;
548 if (sp->lno == 0) {
549 sp->lno = 1;
550 sp->cno = 0;
551 }
552 if (ex_run_str(sp,
553 "-c option", gp->c_option, strlen(gp->c_option), 1, 1))
554 return;
555 gp->c_option = NULL((void *)0);
556 } else if (F_ISSET(sp, SC_EX)(((sp)->flags) & ((0x00000001)))) {
557 if (db_last(sp, &sp->lno))
558 return;
559 if (sp->lno == 0) {
560 sp->lno = 1;
561 sp->cno = 0;
562 return;
563 }
564 nb = 1;
565 } else {
566 if (F_ISSET(sp->frp, FR_CURSORSET)(((sp->frp)->flags) & ((0x0001)))) {
567 sp->lno = sp->frp->lno;
568 sp->cno = sp->frp->cno;
569
570 /* If returning to a file in vi, center the line. */
571 F_SET(sp, SC_SCR_CENTER)(((sp)->flags) |= ((0x00000080)));
572 } else {
573 if (O_ISSET(sp, O_COMMENT)((((&(((sp)))->opts[(((O_COMMENT)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_COMMENT
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_COMMENT)))
].o_cur.val)
)
574 file_comment(sp);
575 else
576 sp->lno = 1;
577 nb = 1;
578 }
579 if (db_get(sp, sp->lno, 0, NULL((void *)0), &len)) {
580 sp->lno = 1;
581 sp->cno = 0;
582 return;
583 }
584 if (!nb && sp->cno > len)
585 nb = 1;
586 }
587 if (nb) {
588 sp->cno = 0;
589 (void)nonblank(sp, sp->lno, &sp->cno);
590 }
591
592 /*
593 * !!!
594 * The initial column is also the most attractive column.
595 */
596 sp->rcm = sp->cno;
597
598 /*
599 * !!!
600 * Historically, vi initialized the absolute mark, but ex did not.
601 * Which meant, that if the first command in ex mode was "visual",
602 * or if an ex command was executed first (e.g. vi +10 file) vi was
603 * entered without the mark being initialized. For consistency, if
604 * the file isn't empty, we initialize it for everyone, believing
605 * that it can't hurt, and is generally useful. Not initializing it
606 * if the file is empty is historic practice, although it has always
607 * been possible to set (and use) marks in empty vi files.
608 */
609 m.lno = sp->lno;
610 m.cno = sp->cno;
611 (void)mark_set(sp, ABSMARK1'\'', &m, 0);
612}
613
614/*
615 * file_end --
616 * Stop editing a file.
617 *
618 * PUBLIC: int file_end(SCR *, EXF *, int);
619 */
620int
621file_end(SCR *sp, EXF *ep, int force)
622{
623 FREF *frp;
624
625 /*
626 * !!!
627 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
628 * (If argument ep is NULL, use sp->ep.)
629 *
630 * If multiply referenced, just decrement the count and return.
631 */
632 if (ep == NULL((void *)0))
633 ep = sp->ep;
634 if (--ep->refcnt != 0)
635 return (0);
636
637 /*
638 *
639 * Clean up the FREF structure.
640 *
641 * Save the cursor location.
642 *
643 * XXX
644 * It would be cleaner to do this somewhere else, but by the time
645 * ex or vi knows that we're changing files it's already happened.
646 */
647 frp = sp->frp;
648 frp->lno = sp->lno;
649 frp->cno = sp->cno;
650 F_SET(frp, FR_CURSORSET)(((frp)->flags) |= ((0x0001)));
651
652 /*
653 * We may no longer need the temporary backing file, so clean it
654 * up. We don't need the FREF structure either, if the file was
655 * never named, so lose it.
656 *
657 * !!!
658 * Re: FR_DONTDELETE, see the comment above in file_init().
659 */
660 if (!F_ISSET(frp, FR_DONTDELETE)(((frp)->flags) & ((0x0002))) && frp->tname != NULL((void *)0)) {
661 if (unlink(frp->tname))
662 msgq_str(sp, M_SYSERR, frp->tname, "%s: remove");
663 free(frp->tname);
664 frp->tname = NULL((void *)0);
665 if (F_ISSET(frp, FR_TMPFILE)(((frp)->flags) & ((0x0080)))) {
666 TAILQ_REMOVE(&sp->gp->frefq, frp, q)do { if (((frp)->q.tqe_next) != ((void *)0)) (frp)->q.tqe_next
->q.tqe_prev = (frp)->q.tqe_prev; else (&sp->gp->
frefq)->tqh_last = (frp)->q.tqe_prev; *(frp)->q.tqe_prev
= (frp)->q.tqe_next; ; ; } while (0)
;
667 free(frp->name);
668 free(frp);
669 }
670 sp->frp = NULL((void *)0);
671 }
672
673 /*
674 * Clean up the EXF structure.
675 *
676 * Close the db structure.
677 */
678 if (ep->db->close != NULL((void *)0) && ep->db->close(ep->db) && !force) {
679 msgq_str(sp, M_SYSERR, frp->name, "%s: close");
680 ++ep->refcnt;
681 return (1);
682 }
683
684 /* COMMITTED TO THE CLOSE. THERE'S NO GOING BACK... */
685
686 /* Stop logging. */
687 (void)log_end(sp, ep);
688
689 /* Free up any marks. */
690 (void)mark_end(sp, ep);
691
692 /*
693 * Delete recovery files, close the open descriptor, free recovery
694 * memory. See recover.c for a description of the protocol.
695 *
696 * XXX
697 * Unlink backup file first, we can detect that the recovery file
698 * doesn't reference anything when the user tries to recover it.
699 * There's a race, here, obviously, but it's fairly small.
700 */
701 if (!F_ISSET(ep, F_RCV_NORM)(((ep)->flags) & ((0x020)))) {
702 if (ep->rcv_path != NULL((void *)0) && unlink(ep->rcv_path))
703 msgq_str(sp, M_SYSERR, ep->rcv_path, "%s: remove");
704 if (ep->rcv_mpath != NULL((void *)0) && unlink(ep->rcv_mpath))
705 msgq_str(sp, M_SYSERR, ep->rcv_mpath, "%s: remove");
706 }
707 if (ep->fcntl_fd != -1)
708 (void)close(ep->fcntl_fd);
709 if (ep->rcv_fd != -1)
710 (void)close(ep->rcv_fd);
711 free(ep->rcv_path);
712 free(ep->rcv_mpath);
713 free(ep);
714 return (0);
715}
716
717/*
718 * file_write --
719 * Write the file to disk. Historic vi had fairly convoluted
720 * semantics for whether or not writes would happen. That's
721 * why all the flags.
722 *
723 * PUBLIC: int file_write(SCR *, MARK *, MARK *, char *, int);
724 */
725int
726file_write(SCR *sp, MARK *fm, MARK *tm, char *name, int flags)
727{
728 enum { NEWFILE, OLDFILE } mtype;
729 struct stat sb;
730 EXF *ep;
731 FILE *fp;
732 FREF *frp;
733 MARK from, to;
734 size_t len;
735 u_long nlno, nch;
736 int fd, nf, noname, oflags, rval;
737 char *p, *s, *t, buf[PATH_MAX1024 + 64];
738 const char *msgstr;
739
740 ep = sp->ep;
741 frp = sp->frp;
742
743 /*
744 * Writing '%', or naming the current file explicitly, has the
745 * same semantics as writing without a name.
746 */
747 if (name == NULL((void *)0) || !strcmp(name, frp->name)) {
748 noname = 1;
749 name = frp->name;
750 } else
751 noname = 0;
752
753 /* Can't write files marked read-only, unless forced. */
754 if (!LF_ISSET(FS_FORCE)((flags) & ((0x004))) && noname && O_ISSET(sp, O_READONLY)((((&(((sp)))->opts[(((O_READONLY)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_READONLY
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_READONLY))
)].o_cur.val)
) {
755 msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE)((flags) & ((0x010))) ?
756 "Read-only file, not written; use ! to override" :
757 "Read-only file, not written");
758 return (1);
759 }
760
761 /* If not forced, not appending, and "writeany" not set ... */
762 if (!LF_ISSET(FS_FORCE | FS_APPEND)((flags) & ((0x004 | 0x002))) && !O_ISSET(sp, O_WRITEANY)((((&(((sp)))->opts[(((O_WRITEANY)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_WRITEANY
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_WRITEANY))
)].o_cur.val)
) {
763 /* Don't overwrite anything but the original file. */
764 if ((!noname || F_ISSET(frp, FR_NAMECHANGE)(((frp)->flags) & ((0x0008)))) &&
765 !stat(name, &sb)) {
766 msgq_str(sp, M_ERR, name,
767 LF_ISSET(FS_POSSIBLE)((flags) & ((0x010))) ?
768 "%s exists, not written; use ! to override" :
769 "%s exists, not written");
770 return (1);
771 }
772
773 /*
774 * Don't write part of any existing file. Only test for the
775 * original file, the previous test catches anything else.
776 */
777 if (!LF_ISSET(FS_ALL)((flags) & ((0x001))) && noname && !stat(name, &sb)) {
778 msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE)((flags) & ((0x010))) ?
779 "Partial file, not written; use ! to override" :
780 "Partial file, not written");
781 return (1);
782 }
783 }
784
785 /*
786 * Figure out if the file already exists -- if it doesn't, we display
787 * the "new file" message. The stat might not be necessary, but we
788 * just repeat it because it's easier than hacking the previous tests.
789 * The information is only used for the user message and modification
790 * time test, so we can ignore the obvious race condition.
791 *
792 * One final test. If we're not forcing or appending the current file,
793 * and we have a saved modification time, object if the file changed
794 * since we last edited or wrote it, and make them force it.
795 */
796 if (stat(name, &sb))
797 mtype = NEWFILE;
798 else {
799 if (noname && !LF_ISSET(FS_FORCE | FS_APPEND)((flags) & ((0x004 | 0x002))) &&
800 ((F_ISSET(ep, F_DEVSET)(((ep)->flags) & ((0x001))) &&
801 (sb.st_dev != ep->mdev || sb.st_ino != ep->minode)) ||
802 timespeccmp(&sb.st_mtim, &ep->mtim, !=)(((&sb.st_mtim)->tv_sec == (&ep->mtim)->tv_sec
) ? ((&sb.st_mtim)->tv_nsec != (&ep->mtim)->
tv_nsec) : ((&sb.st_mtim)->tv_sec != (&ep->mtim
)->tv_sec))
)) {
803 msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE)((flags) & ((0x010))) ?
804"%s: file modified more recently than this copy; use ! to override" :
805"%s: file modified more recently than this copy");
806 return (1);
807 }
808
809 mtype = OLDFILE;
810 }
811
812 /* Set flags to create, write, and either append or truncate. */
813 oflags = O_CREAT0x0200 | O_WRONLY0x0001 |
814 (LF_ISSET(FS_APPEND)((flags) & ((0x002))) ? O_APPEND0x0008 : O_TRUNC0x0400);
815
816 /* Backup the file if requested. */
817 if (!opts_empty(sp, O_BACKUP, 1) &&
818 file_backup(sp, name, O_STR(sp, O_BACKUP)((((&((sp))->opts[((O_BACKUP))])->flags) & ((0x01
))) ? ((sp))->gp->opts[((sp))->opts[((O_BACKUP))].o_cur
.val].o_cur.str : ((sp))->opts[((O_BACKUP))].o_cur.str)
) && !LF_ISSET(FS_FORCE)((flags) & ((0x004))))
819 return (1);
820
821 /* Open the file. */
822 if ((fd = open(name, oflags,
823 S_IRUSR0000400 | S_IWUSR0000200 | S_IRGRP0000040 | S_IWGRP0000020 | S_IROTH0000004 | S_IWOTH0000002)) < 0) {
824 msgq_str(sp, M_SYSERR, name, "%s");
825 return (1);
826 }
827
828 /* Try and get a lock. */
829 if (!noname && file_lock(sp, NULL((void *)0), NULL((void *)0), fd, 0) == LOCK_UNAVAIL)
830 msgq_str(sp, M_ERR, name,
831 "%s: write lock was unavailable");
832
833 /*
834 * Use stdio for buffering.
835 *
836 * XXX
837 * SVR4.2 requires the fdopen mode exactly match the original open
838 * mode, i.e. you have to open with "a" if appending.
839 */
840 if ((fp = fdopen(fd, LF_ISSET(FS_APPEND)((flags) & ((0x002))) ? "a" : "w")) == NULL((void *)0)) {
841 msgq_str(sp, M_SYSERR, name, "%s");
842 (void)close(fd);
843 return (1);
844 }
845
846 /* Build fake addresses, if necessary. */
847 if (fm == NULL((void *)0)) {
848 from.lno = 1;
849 from.cno = 0;
850 fm = &from;
851 if (db_last(sp, &to.lno))
852 return (1);
853 to.cno = 0;
854 tm = &to;
855 }
856
857 rval = ex_writefp(sp, name, fp, fm, tm, &nlno, &nch, 0);
858
859 /*
860 * Save the new last modification time -- even if the write fails
861 * we re-init the time. That way the user can clean up the disk
862 * and rewrite without having to force it.
863 */
864 if (noname) {
865 if (stat(name, &sb))
866 (void)clock_gettime(CLOCK_REALTIME0, &ep->mtim);
867 else {
868 F_SET(ep, F_DEVSET)(((ep)->flags) |= ((0x001)));
869 ep->mdev = sb.st_dev;
870 ep->minode = sb.st_ino;
871
872 ep->mtim = sb.st_mtim;
873 }
874 }
875
876 /*
877 * If the write failed, complain loudly. ex_writefp() has already
878 * complained about the actual error, reinforce it if data was lost.
879 */
880 if (rval) {
881 if (!LF_ISSET(FS_APPEND)((flags) & ((0x002))))
882 msgq_str(sp, M_ERR, name,
883 "%s: WARNING: FILE TRUNCATED");
884 return (1);
885 }
886
887 /*
888 * Once we've actually written the file, it doesn't matter that the
889 * file name was changed -- if it was, we've already whacked it.
890 */
891 F_CLR(frp, FR_NAMECHANGE)(((frp)->flags) &= ~((0x0008)));
892
893 /*
894 * If wrote the entire file, and it wasn't by appending it to a file,
895 * clear the modified bit. If the file was written to the original
896 * file name and the file is a temporary, set the "no exit" bit. This
897 * permits the user to write the file and use it in the context of the
898 * filesystem, but still keeps them from discarding their changes by
899 * exiting.
900 */
901 if (LF_ISSET(FS_ALL)((flags) & ((0x001))) && !LF_ISSET(FS_APPEND)((flags) & ((0x002)))) {
902 F_CLR(ep, F_MODIFIED)(((ep)->flags) &= ~((0x004)));
903 if (F_ISSET(frp, FR_TMPFILE)(((frp)->flags) & ((0x0080)))) {
904 if (noname)
905 F_SET(frp, FR_TMPEXIT)(((frp)->flags) |= ((0x0040)));
906 else
907 F_CLR(frp, FR_TMPEXIT)(((frp)->flags) &= ~((0x0040)));
908 }
909 }
910
911 p = msg_print(sp, name, &nf);
912 switch (mtype) {
913 case NEWFILE:
914 len = snprintf(buf, sizeof(buf),
915 "%s: new file: %lu lines, %lu characters", p, nlno, nch);
916 if (len >= sizeof(buf))
917 len = sizeof(buf) - 1;
918 break;
919 case OLDFILE:
920 msgstr = LF_ISSET(FS_APPEND)((flags) & ((0x002))) ?
921 "%s: appended: %lu lines, %lu characters" :
922 "%s: %lu lines, %lu characters";
923 len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch);
924 if (len >= sizeof(buf))
925 len = sizeof(buf) - 1;
926 break;
927 default:
928 abort();
929 }
930
931 /*
932 * There's a nasty problem with long path names. Tags files
933 * can result in long paths and vi will request a continuation key from
934 * the user. Unfortunately, the user has typed ahead, and chaos will
935 * result. If we assume that the characters in the filenames only take
936 * a single screen column each, we can trim the filename.
937 */
938 s = buf;
939 if (len >= sp->cols) {
940 for (s = buf, t = buf + strlen(p); s < t &&
941 (*s != '/' || len >= sp->cols - 3); ++s, --len);
942 if (s == t)
943 s = buf;
944 else {
945 *--s = '.'; /* Leading ellipses. */
946 *--s = '.';
947 *--s = '.';
948 }
949 }
950 msgq(sp, M_INFO, "%s", s);
951 if (nf)
952 FREE_SPACE(sp, p, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(p); }
;
953 return (0);
954}
955
956/*
957 * file_backup --
958 * Backup the about-to-be-written file.
959 *
960 * XXX
961 * We do the backup by copying the entire file. It would be nice to do
962 * a rename instead, but: (1) both files may not fit and we want to fail
963 * before doing the rename; (2) the backup file may not be on the same
964 * disk partition as the file being written; (3) there may be optional
965 * file information (MACs, DACs, whatever) that we won't get right if we
966 * recreate the file. So, let's not risk it.
967 */
968static int
969file_backup(SCR *sp, char *name, char *bname)
970{
971 struct dirent *dp;
972 struct stat sb;
973 DIR *dirp;
974 EXCMD cmd;
975 off_t off;
976 size_t blen;
977 int flags, maxnum, nr, num, nw, rfd, wfd, version;
978 char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192];
979
980 rfd = wfd = -1;
981 bp = estr = wfname = NULL((void *)0);
982
983 /*
984 * Open the current file for reading. Do this first, so that
985 * we don't exec a shell before the most likely failure point.
986 * If it doesn't exist, it's okay, there's just nothing to back
987 * up.
988 */
989 errno(*__errno()) = 0;
990 if ((rfd = open(name, O_RDONLY0x0000)) < 0) {
991 if (errno(*__errno()) == ENOENT2)
992 return (0);
993 estr = name;
994 goto err;
995 }
996
997 /*
998 * If the name starts with an 'N' character, add a version number
999 * to the name. Strip the leading N from the string passed to the
1000 * expansion routines, for no particular reason. It would be nice
1001 * to permit users to put the version number anywhere in the backup
1002 * name, but there isn't a special character that we can use in the
1003 * name, and giving a new character a special meaning leads to ugly
1004 * hacks both here and in the supporting ex routines.
1005 *
1006 * Shell and file name expand the option's value.
1007 */
1008 argv_init(sp, &cmd);
1009 ex_cinit(&cmd, 0, 0, 0, 0, 0, NULL((void *)0));
1010 if (bname[0] == 'N') {
1011 version = 1;
1012 ++bname;
1013 } else
1014 version = 0;
1015 if (argv_exp2(sp, &cmd, bname, strlen(bname)))
1016 return (1);
1017
1018 /*
1019 * 0 args: impossible.
1020 * 1 args: use it.
1021 * >1 args: object, too many args.
1022 */
1023 if (cmd.argc != 1) {
1024 msgq_str(sp, M_ERR, bname,
1025 "%s expanded into too many file names");
1026 (void)close(rfd);
1027 return (1);
1028 }
1029
1030 /*
1031 * If appending a version number, read through the directory, looking
1032 * for file names that match the name followed by a number. Make all
1033 * of the other % characters in name literal, so the user doesn't get
1034 * surprised and sscanf doesn't drop core indirecting through pointers
1035 * that don't exist. If any such files are found, increment its number
1036 * by one.
1037 */
1038 if (version) {
1039 GET_SPACE_GOTO(sp, bp, blen, cmd.argv[0]->len * 2 + 50){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((cmd.argv[0]->len * 2 + 50)) > ((blen))) { if ((L__bincp
= binc(((sp)), ((bp)), &((blen)), ((cmd.argv[0]->len *
2 + 50)))) == ((void *)0)) goto alloc_err; ((bp)) = L__bincp
; } }; } else { { void *L__bincp; if (((cmd.argv[0]->len *
2 + 50)) > (L__gp->tmp_blen)) { if ((L__bincp = binc((
(sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen), ((cmd.argv
[0]->len * 2 + 50)))) == ((void *)0)) goto alloc_err; (L__gp
->tmp_bp) = L__bincp; } }; (bp) = L__gp->tmp_bp; (blen)
= L__gp->tmp_blen; (((L__gp)->flags) |= ((0x0100))); }
}
;
1040 for (t = bp, slash = NULL((void *)0),
1041 p = cmd.argv[0]->bp; p[0] != '\0'; *t++ = *p++)
1042 if (p[0] == '%') {
1043 if (p[1] != '%')
1044 *t++ = '%';
1045 } else if (p[0] == '/')
1046 slash = t;
1047 pct = t;
1048 *t++ = '%';
1049 *t++ = 'd';
1050 *t = '\0';
1051
1052 if (slash == NULL((void *)0)) {
1053 dirp = opendir(".");
1054 p = bp;
1055 } else {
1056 *slash = '\0';
1057 dirp = opendir(bp);
1058 *slash = '/';
1059 p = slash + 1;
1060 }
1061 if (dirp == NULL((void *)0)) {
1062 estr = cmd.argv[0]->bp;
1063 goto err;
1064 }
1065
1066 for (maxnum = 0; (dp = readdir(dirp)) != NULL((void *)0);)
1067 if (sscanf(dp->d_name, p, &num) == 1 && num > maxnum)
1068 maxnum = num;
1069 (void)closedir(dirp);
1070
1071 /* Format the backup file name. */
1072 (void)snprintf(pct, blen - (pct - bp), "%d", maxnum + 1);
1073 wfname = bp;
1074 } else {
1075 bp = NULL((void *)0);
1076 wfname = cmd.argv[0]->bp;
1077 }
1078
1079 /* Open the backup file, avoiding lurkers. */
1080 if (stat(wfname, &sb) == 0) {
1081 if (!S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)) {
1082 msgq_str(sp, M_ERR, bname,
1083 "%s: not a regular file");
1084 goto err;
1085 }
1086 if (sb.st_uid != getuid()) {
1087 msgq_str(sp, M_ERR, bname, "%s: not owned by you");
1088 goto err;
1089 }
1090 if (sb.st_mode & (S_IRGRP0000040 | S_IWGRP0000020 | S_IROTH0000004 | S_IWOTH0000002)) {
1091 msgq_str(sp, M_ERR, bname,
1092 "%s: accessible by a user other than the owner");
1093 goto err;
1094 }
1095 flags = O_TRUNC0x0400;
1096 } else
1097 flags = O_CREAT0x0200 | O_EXCL0x0800;
1098 if ((wfd = open(wfname, flags | O_WRONLY0x0001, S_IRUSR0000400 | S_IWUSR0000200)) < 0 ||
1099 fchmod(wfd, S_IRUSR0000400 | S_IWUSR0000200) < 0) {
1100 if (wfd != -1) {
1101 close(wfd);
1102 (void)unlink(wfname);
1103 }
1104 estr = bname;
1105 goto err;
1106 }
1107
1108 /* Copy the file's current contents to its backup value. */
1109 while ((nr = read(rfd, buf, sizeof(buf))) > 0)
1110 for (off = 0; nr != 0; nr -= nw, off += nw)
1111 if ((nw = write(wfd, buf + off, nr)) < 0) {
1112 estr = wfname;
1113 goto err;
1114 }
1115 if (nr < 0) {
1116 estr = name;
1117 goto err;
1118 }
1119
1120 if (close(rfd)) {
1121 estr = name;
1122 goto err;
1123 }
1124 if (close(wfd)) {
1125 estr = wfname;
1126 goto err;
1127 }
1128 if (bp != NULL((void *)0))
1129 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
1130 return (0);
1131
1132alloc_err:
1133err: if (rfd != -1)
1134 (void)close(rfd);
1135 if (wfd != -1) {
1136 (void)unlink(wfname);
1137 (void)close(wfd);
1138 }
1139 if (estr)
1140 msgq_str(sp, M_SYSERR, estr, "%s");
1141 if (bp != NULL((void *)0))
1142 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
1143 return (1);
1144}
1145
1146/*
1147 * file_comment --
1148 * Skip the first comment.
1149 */
1150static void
1151file_comment(SCR *sp)
1152{
1153 recno_t lno;
1154 size_t len;
1155 char *p;
1156
1157 for (lno = 1; !db_get(sp, lno, 0, &p, &len) && len == 0; ++lno);
1158 if (p == NULL((void *)0))
1159 return;
1160 if (p[0] == '#') {
1161 F_SET(sp, SC_SCR_TOP)(((sp)->flags) |= ((0x00000100)));
1162 while (!db_get(sp, ++lno, 0, &p, &len))
1163 if (len < 1 || p[0] != '#') {
1164 sp->lno = lno;
1165 return;
1166 }
1167 } else if (len > 1 && p[0] == '/' && p[1] == '*') {
1168 F_SET(sp, SC_SCR_TOP)(((sp)->flags) |= ((0x00000100)));
1169 do {
1170 for (; len > 1; --len, ++p)
1171 if (p[0] == '*' && p[1] == '/') {
1172 sp->lno = lno;
1173 return;
1174 }
1175 } while (!db_get(sp, ++lno, 0, &p, &len));
1176 } else if (len > 1 && p[0] == '/' && p[1] == '/') {
1177 F_SET(sp, SC_SCR_TOP)(((sp)->flags) |= ((0x00000100)));
1178 p += 2;
1179 len -= 2;
1180 do {
1181 for (; len > 1; --len, ++p)
1182 if (p[0] == '/' && p[1] == '/') {
1183 sp->lno = lno;
1184 return;
1185 }
1186 } while (!db_get(sp, ++lno, 0, &p, &len));
1187 }
1188}
1189
1190/*
1191 * file_m1 --
1192 * First modification check routine. The :next, :prev, :rewind, :tag,
1193 * :tagpush, :tagpop, ^^ modifications check.
1194 *
1195 * PUBLIC: int file_m1(SCR *, int, int);
1196 */
1197int
1198file_m1(SCR *sp, int force, int flags)
1199{
1200 EXF *ep;
1201
1202 ep = sp->ep;
1203
1204 /* If no file loaded, return no modifications. */
1205 if (ep == NULL((void *)0))
1206 return (0);
1207
1208 /*
1209 * If the file has been modified, we'll want to write it back or
1210 * fail. If autowrite is set, we'll write it back automatically,
1211 * unless force is also set. Otherwise, we fail unless forced or
1212 * there's another open screen on this file.
1213 */
1214 if (F_ISSET(ep, F_MODIFIED)(((ep)->flags) & ((0x004)))) {
1215 if (O_ISSET(sp, O_AUTOWRITE)((((&(((sp)))->opts[(((O_AUTOWRITE)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_AUTOWRITE
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_AUTOWRITE)
))].o_cur.val)
) {
1216 if (!force && file_aw(sp, flags))
1217 return (1);
1218 } else if (ep->refcnt <= 1 && !force) {
1219 msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE)((flags) & ((0x010))) ?
1220"File modified since last complete write; write or use ! to override" :
1221"File modified since last complete write; write or use :edit! to override");
1222 return (1);
1223 }
1224 }
1225
1226 return (file_m3(sp, force));
1227}
1228
1229/*
1230 * file_m2 --
1231 * Second modification check routine. The :edit, :quit, :recover
1232 * modifications check.
1233 *
1234 * PUBLIC: int file_m2(SCR *, int);
1235 */
1236int
1237file_m2(SCR *sp, int force)
1238{
1239 EXF *ep;
1240
1241 ep = sp->ep;
1242
1243 /* If no file loaded, return no modifications. */
1244 if (ep == NULL((void *)0))
1245 return (0);
1246
1247 /*
1248 * If the file has been modified, we'll want to fail, unless forced
1249 * or there's another open screen on this file.
1250 */
1251 if (F_ISSET(ep, F_MODIFIED)(((ep)->flags) & ((0x004))) && ep->refcnt <= 1 && !force) {
1252 msgq(sp, M_ERR,
1253"File modified since last complete write; write or use ! to override");
1254 return (1);
1255 }
1256
1257 return (file_m3(sp, force));
1258}
1259
1260/*
1261 * file_m3 --
1262 * Third modification check routine.
1263 *
1264 * PUBLIC: int file_m3(SCR *, int);
1265 */
1266int
1267file_m3(SCR *sp, int force)
1268{
1269 EXF *ep;
1270
1271 ep = sp->ep;
1272
1273 /* If no file loaded, return no modifications. */
1274 if (ep == NULL((void *)0))
1275 return (0);
1276
1277 /*
1278 * Don't exit while in a temporary files if the file was ever modified.
1279 * The problem is that if the user does a ":wq", we write and quit,
1280 * unlinking the temporary file. Not what the user had in mind at all.
1281 * We permit writing to temporary files, so that user maps using file
1282 * system names work with temporary files.
1283 */
1284 if (F_ISSET(sp->frp, FR_TMPEXIT)(((sp->frp)->flags) & ((0x0040))) && ep->refcnt <= 1 && !force) {
1285 msgq(sp, M_ERR,
1286 "File is a temporary; exit will discard modifications");
1287 return (1);
1288 }
1289 return (0);
1290}
1291
1292/*
1293 * file_aw --
1294 * Autowrite routine. If modified, autowrite is set and the readonly bit
1295 * is not set, write the file. A routine so there's a place to put the
1296 * comment.
1297 *
1298 * PUBLIC: int file_aw(SCR *, int);
1299 */
1300int
1301file_aw(SCR *sp, int flags)
1302{
1303 if (!F_ISSET(sp->ep, F_MODIFIED)(((sp->ep)->flags) & ((0x004))))
1304 return (0);
1305 if (!O_ISSET(sp, O_AUTOWRITE)((((&(((sp)))->opts[(((O_AUTOWRITE)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_AUTOWRITE
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_AUTOWRITE)
))].o_cur.val)
)
1306 return (0);
1307
1308 /*
1309 * !!!
1310 * Historic 4BSD vi attempted to write the file if autowrite was set,
1311 * regardless of the writeability of the file (as defined by the file
1312 * readonly flag). System V changed this as some point, not attempting
1313 * autowrite if the file was readonly. This feels like a bug fix to
1314 * me (e.g. the principle of least surprise is violated if readonly is
1315 * set and vi writes the file), so I'm compatible with System V.
1316 */
1317 if (O_ISSET(sp, O_READONLY)((((&(((sp)))->opts[(((O_READONLY)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_READONLY
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_READONLY))
)].o_cur.val)
) {
1318 msgq(sp, M_INFO,
1319 "File readonly, modifications not auto-written");
1320 return (1);
1321 }
1322 return (file_write(sp, NULL((void *)0), NULL((void *)0), NULL((void *)0), flags));
1323}
1324
1325/*
1326 * set_alt_name --
1327 * Set the alternate pathname.
1328 *
1329 * Set the alternate pathname. It's a routine because I wanted some place
1330 * to hang this comment. The alternate pathname (normally referenced using
1331 * the special character '#' during file expansion and in the vi ^^ command)
1332 * is set by almost all ex commands that take file names as arguments. The
1333 * rules go something like this:
1334 *
1335 * 1: If any ex command takes a file name as an argument (except for the
1336 * :next command), the alternate pathname is set to that file name.
1337 * This excludes the command ":e" and ":w !command" as no file name
1338 * was specified. Note, historically, the :source command did not set
1339 * the alternate pathname. It does in nvi, for consistency.
1340 *
1341 * 2: However, if any ex command sets the current pathname, e.g. the
1342 * ":e file" or ":rew" commands succeed, then the alternate pathname
1343 * is set to the previous file's current pathname, if it had one.
1344 * This includes the ":file" command and excludes the ":e" command.
1345 * So, by rule #1 and rule #2, if ":edit foo" fails, the alternate
1346 * pathname will be "foo", if it succeeds, the alternate pathname will
1347 * be the previous current pathname. The ":e" command will not set
1348 * the alternate or current pathnames regardless.
1349 *
1350 * 3: However, if it's a read or write command with a file argument and
1351 * the current pathname has not yet been set, the file name becomes
1352 * the current pathname, and the alternate pathname is unchanged.
1353 *
1354 * If the user edits a temporary file, there may be times when there is no
1355 * alternative file name. A name argument of NULL turns it off.
1356 *
1357 * PUBLIC: void set_alt_name(SCR *, char *);
1358 */
1359void
1360set_alt_name(SCR *sp, char *name)
1361{
1362 free(sp->alt_name);
1363 if (name == NULL((void *)0))
1364 sp->alt_name = NULL((void *)0);
1365 else if ((sp->alt_name = strdup(name)) == NULL((void *)0))
1366 msgq(sp, M_SYSERR, NULL((void *)0));
1367}
1368
1369/*
1370 * file_lock --
1371 * Get an exclusive lock on a file.
1372 *
1373 * PUBLIC: lockr_t file_lock(SCR *, char *, int *, int, int);
1374 */
1375lockr_t
1376file_lock(SCR *sp, char *name, int *fdp, int fd, int iswrite)
1377{
1378 if (!O_ISSET(sp, O_LOCKFILES)((((&(((sp)))->opts[(((O_LOCKFILES)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_LOCKFILES
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_LOCKFILES)
))].o_cur.val)
)
1379 return (LOCK_SUCCESS);
1380
1381 /* Set close-on-exec flag so locks are not inherited by shell cmd. */
1382 if (fcntl(fd, F_SETFD2, FD_CLOEXEC1) == -1)
1383 msgq_str(sp, M_SYSERR, name, "%s");
1384
1385 /*
1386 * !!!
1387 * We need to distinguish a lock not being available for the file
1388 * from the file system not supporting locking. Flock is documented
1389 * as returning EWOULDBLOCK; add EAGAIN for good measure, and assume
1390 * they are the former. There's no portable way to do this.
1391 */
1392 errno(*__errno()) = 0;
1393 return (flock(fd, LOCK_EX0x02 | LOCK_NB0x04) ?
1394 errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EWOULDBLOCK35 ? LOCK_UNAVAIL : LOCK_FAILED :
1395 LOCK_SUCCESS);
1396}