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