source: trunk/third/nvi/common/exf.c @ 14302

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