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