summaryrefslogtreecommitdiffstats
path: root/contrib/nvi/common/exf.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/nvi/common/exf.c')
-rw-r--r--contrib/nvi/common/exf.c402
1 files changed, 193 insertions, 209 deletions
diff --git a/contrib/nvi/common/exf.c b/contrib/nvi/common/exf.c
index b0c438d..6579ab2 100644
--- a/contrib/nvi/common/exf.c
+++ b/contrib/nvi/common/exf.c
@@ -5,23 +5,18 @@
* Keith Bostic. All rights reserved.
*
* See the LICENSE file for redistribution information.
- *
*/
#include "config.h"
#ifndef lint
-#if 0
-static const char sccsid[] = "@(#)exf.c 10.49 (Berkeley) 10/10/96";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
+static const char sccsid[] = "$Id: exf.c,v 10.62 2013/07/01 23:28:13 zy Exp $";
#endif /* not lint */
-#include <sys/param.h>
-#include <sys/types.h> /* XXX: param.h may not have included types.h */
+#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
+#include <sys/time.h>
/*
* We include <sys/file.h>, because the flock(2) and open(2) #defines
@@ -44,6 +39,7 @@ static const char rcsid[] =
static int file_backup __P((SCR *, char *, char *));
static void file_cinit __P((SCR *));
+static void file_encinit __P((SCR *));
static void file_comment __P((SCR *));
static int file_spath __P((SCR *, FREF *, struct stat *, int *));
@@ -60,12 +56,12 @@ static int file_spath __P((SCR *, FREF *, struct stat *, int *));
* vi now remembers the last location in any file that it has ever edited,
* not just the previously edited file.
*
- * PUBLIC: FREF *file_add __P((SCR *, CHAR_T *));
+ * PUBLIC: FREF *file_add __P((SCR *, char *));
*/
FREF *
-file_add(sp, name)
- SCR *sp;
- CHAR_T *name;
+file_add(
+ SCR *sp,
+ char *name)
{
GS *gp;
FREF *frp, *tfrp;
@@ -81,15 +77,12 @@ file_add(sp, name)
*/
gp = sp->gp;
if (name != NULL)
- for (frp = gp->frefq.cqh_first;
- frp != (FREF *)&gp->frefq; frp = frp->q.cqe_next) {
+ TAILQ_FOREACH_SAFE(frp, gp->frefq, q, tfrp) {
if (frp->name == NULL) {
- tfrp = frp->q.cqe_next;
- CIRCLEQ_REMOVE(&gp->frefq, frp, q);
+ TAILQ_REMOVE(gp->frefq, frp, q);
if (frp->name != NULL)
free(frp->name);
free(frp);
- frp = tfrp;
continue;
}
if (!strcmp(frp->name, name))
@@ -114,7 +107,7 @@ file_add(sp, name)
}
/* Append into the chain of file names. */
- CIRCLEQ_INSERT_TAIL(&gp->frefq, frp, q);
+ TAILQ_INSERT_TAIL(gp->frefq, frp, q);
return (frp);
}
@@ -128,18 +121,18 @@ file_add(sp, name)
* PUBLIC: int file_init __P((SCR *, FREF *, char *, int));
*/
int
-file_init(sp, frp, rcv_name, flags)
- SCR *sp;
- FREF *frp;
- char *rcv_name;
- int flags;
+file_init(
+ SCR *sp,
+ FREF *frp,
+ char *rcv_name,
+ int flags)
{
EXF *ep;
- RECNOINFO oinfo;
+ RECNOINFO oinfo = { 0 };
struct stat sb;
size_t psize;
int fd, exists, open_err, readonly;
- char *oname, tname[MAXPATHLEN];
+ char *oname, *tname;
open_err = readonly = 0;
@@ -169,7 +162,7 @@ file_init(sp, frp, rcv_name, flags)
*/
CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF));
ep->c_lno = ep->c_nlines = OOBLNO;
- ep->rcv_fd = ep->fcntl_fd = -1;
+ ep->rcv_fd = -1;
F_SET(ep, F_FIRSTMODIFY);
/*
@@ -187,52 +180,56 @@ file_init(sp, frp, rcv_name, flags)
*/
oname = frp->name;
if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) {
- if (opts_empty(sp, O_TMP_DIRECTORY, 0))
+ struct stat sb;
+
+ if (opts_empty(sp, O_TMPDIR, 0))
+ goto err;
+ if ((tname =
+ join(O_STR(sp, O_TMPDIR), "vi.XXXXXXXXXX")) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
goto err;
- (void)snprintf(tname, sizeof(tname),
- "%s/vi.XXXXXXXXXX", O_STR(sp, O_TMP_DIRECTORY));
- if ((fd = mkstemp(tname)) == -1) {
+ }
+ if ((fd = mkstemp(tname)) == -1 || fstat(fd, &sb)) {
+ free(tname);
msgq(sp, M_SYSERR,
"237|Unable to create temporary file");
goto err;
}
(void)close(fd);
- if (frp->name == NULL)
+ frp->tname = tname;
+ if (frp->name == NULL) {
F_SET(frp, FR_TMPFILE);
- if ((frp->tname = strdup(tname)) == NULL ||
- frp->name == NULL && (frp->name = strdup(tname)) == NULL) {
- if (frp->tname != NULL)
- free(frp->tname);
- msgq(sp, M_SYSERR, NULL);
- (void)unlink(tname);
- goto err;
+ if ((frp->name = strdup(tname)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ goto err;
+ }
}
oname = frp->tname;
psize = 1024;
if (!LF_ISSET(FS_OPENERR))
F_SET(frp, FR_NEWFILE);
- time(&ep->mtime);
+ ep->mtim = sb.st_mtimespec;
} else {
/*
* XXX
* A seat of the pants calculation: try to keep the file in
- * 15 pages or less. Don't use a page size larger than 10K
+ * 15 pages or less. Don't use a page size larger than 16K
* (vi should have good locality) or smaller than 1K.
*/
psize = ((sb.st_size / 15) + 1023) / 1024;
- if (psize > 10)
- psize = 10;
+ if (psize > 16)
+ psize = 16;
if (psize == 0)
psize = 1;
- psize *= 1024;
+ psize = p2roundup(psize) << 10;
F_SET(ep, F_DEVSET);
ep->mdev = sb.st_dev;
ep->minode = sb.st_ino;
- ep->mtime = sb.st_mtime;
+ ep->mtim = sb.st_mtimespec;
if (!S_ISREG(sb.st_mode))
msgq_str(sp, M_ERR, oname,
@@ -240,7 +237,6 @@ file_init(sp, frp, rcv_name, flags)
}
/* Set up recovery. */
- memset(&oinfo, 0, sizeof(RECNOINFO));
oinfo.bval = '\n'; /* Always set. */
oinfo.psize = psize;
oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0;
@@ -338,8 +334,7 @@ file_init(sp, frp, rcv_name, flags)
* an error.
*/
if (rcv_name == NULL)
- switch (file_lock(sp, oname,
- &ep->fcntl_fd, ep->db->fd(ep->db), 0)) {
+ switch (file_lock(sp, oname, ep->db->fd(ep->db), 0)) {
case LOCK_FAILED:
F_SET(frp, FR_UNLOCKED);
break;
@@ -396,9 +391,9 @@ file_init(sp, frp, rcv_name, flags)
* probably isn't a problem for vi when it's running standalone.
*/
if (readonly || F_ISSET(sp, SC_READONLY) ||
- !F_ISSET(frp, FR_NEWFILE) &&
+ (!F_ISSET(frp, FR_NEWFILE) &&
(!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) ||
- access(frp->name, W_OK)))
+ access(frp->name, W_OK))))
O_SET(sp, O_READONLY);
else
O_CLR(sp, O_READONLY);
@@ -408,6 +403,9 @@ file_init(sp, frp, rcv_name, flags)
sp->ep = ep;
sp->frp = frp;
+ /* Detect and set the file encoding */
+ file_encinit(sp);
+
/* Set the initial cursor position, queue initial command. */
file_cinit(sp);
@@ -446,16 +444,16 @@ oerr: if (F_ISSET(ep, F_RCV_ON))
* try and open.
*/
static int
-file_spath(sp, frp, sbp, existsp)
- SCR *sp;
- FREF *frp;
- struct stat *sbp;
- int *existsp;
+file_spath(
+ SCR *sp,
+ FREF *frp,
+ struct stat *sbp,
+ int *existsp)
{
- CHAR_T savech;
+ int savech;
size_t len;
int found;
- char *name, *p, *t, path[MAXPATHLEN];
+ char *name, *p, *t, *path;
/*
* If the name is NULL or an explicit reference (i.e., the first
@@ -466,8 +464,8 @@ file_spath(sp, frp, sbp, existsp)
*existsp = 0;
return (0);
}
- if (name[0] == '/' || name[0] == '.' &&
- (name[1] == '/' || name[1] == '.' && name[2] == '/')) {
+ if (name[0] == '/' || (name[0] == '.' &&
+ (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) {
*existsp = !stat(name, sbp);
return (0);
}
@@ -481,16 +479,24 @@ file_spath(sp, frp, sbp, existsp)
/* Try the O_PATH option values. */
for (found = 0, p = t = O_STR(sp, O_PATH);; ++p)
if (*p == ':' || *p == '\0') {
- if (t < p - 1) {
+ /*
+ * Ignore the empty strings and ".", since we've already
+ * tried the current directory.
+ */
+ if (t < p && (p - t != 1 || *t != '.')) {
savech = *p;
*p = '\0';
- len = snprintf(path,
- sizeof(path), "%s/%s", t, name);
+ if ((path = join(t, name)) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ break;
+ }
+ len = strlen(path);
*p = savech;
if (!stat(path, sbp)) {
found = 1;
break;
}
+ free(path);
}
t = p + 1;
if (*p == '\0')
@@ -499,10 +505,8 @@ file_spath(sp, frp, sbp, existsp)
/* If we found it, build a new pathname and discard the old one. */
if (found) {
- MALLOC_RET(sp, p, char *, len + 1);
- memcpy(p, path, len + 1);
free(frp->name);
- frp->name = p;
+ frp->name = path;
}
*existsp = found;
return (0);
@@ -513,13 +517,14 @@ file_spath(sp, frp, sbp, existsp)
* Set up the initial cursor position.
*/
static void
-file_cinit(sp)
- SCR *sp;
+file_cinit(SCR *sp)
{
GS *gp;
MARK m;
size_t len;
int nb;
+ CHAR_T *wp;
+ size_t wlen;
/* Set some basic defaults. */
sp->lno = 1;
@@ -553,8 +558,9 @@ file_cinit(sp)
sp->lno = 1;
sp->cno = 0;
}
- if (ex_run_str(sp,
- "-c option", gp->c_option, strlen(gp->c_option), 1, 1))
+ CHAR2INT(sp, gp->c_option, strlen(gp->c_option) + 1,
+ wp, wlen);
+ if (ex_run_str(sp, "-c option", wp, wlen - 1, 1, 1))
return;
gp->c_option = NULL;
} else if (F_ISSET(sp, SC_EX)) {
@@ -622,10 +628,10 @@ file_cinit(sp)
* PUBLIC: int file_end __P((SCR *, EXF *, int));
*/
int
-file_end(sp, ep, force)
- SCR *sp;
- EXF *ep;
- int force;
+file_end(
+ SCR *sp,
+ EXF *ep,
+ int force)
{
FREF *frp;
@@ -670,7 +676,7 @@ file_end(sp, ep, force)
free(frp->tname);
frp->tname = NULL;
if (F_ISSET(frp, FR_TMPFILE)) {
- CIRCLEQ_REMOVE(&sp->gp->frefq, frp, q);
+ TAILQ_REMOVE(sp->gp->frefq, frp, q);
if (frp->name != NULL)
free(frp->name);
free(frp);
@@ -712,14 +718,14 @@ file_end(sp, ep, force)
if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath))
msgq_str(sp, M_SYSERR, ep->rcv_mpath, "243|%s: remove");
}
- if (ep->fcntl_fd != -1)
- (void)close(ep->fcntl_fd);
if (ep->rcv_fd != -1)
(void)close(ep->rcv_fd);
if (ep->rcv_path != NULL)
free(ep->rcv_path);
if (ep->rcv_mpath != NULL)
free(ep->rcv_mpath);
+ if (ep->c_blen > 0)
+ free(ep->c_lp);
free(ep);
return (0);
@@ -734,11 +740,12 @@ file_end(sp, ep, force)
* PUBLIC: int file_write __P((SCR *, MARK *, MARK *, char *, int));
*/
int
-file_write(sp, fm, tm, name, flags)
- SCR *sp;
- MARK *fm, *tm;
- char *name;
- int flags;
+file_write(
+ SCR *sp,
+ MARK *fm,
+ MARK *tm,
+ char *name,
+ int flags)
{
enum { NEWFILE, OLDFILE } mtype;
struct stat sb;
@@ -749,7 +756,7 @@ file_write(sp, fm, tm, name, flags)
size_t len;
u_long nlno, nch;
int fd, nf, noname, oflags, rval;
- char *p, *s, *t, buf[MAXPATHLEN + 64];
+ char *p, *s, *t, buf[1024];
const char *msgstr;
ep = sp->ep;
@@ -812,9 +819,9 @@ file_write(sp, fm, tm, name, flags)
mtype = NEWFILE;
else {
if (noname && !LF_ISSET(FS_FORCE | FS_APPEND) &&
- (F_ISSET(ep, F_DEVSET) &&
- (sb.st_dev != ep->mdev || sb.st_ino != ep->minode) ||
- sb.st_mtime != ep->mtime)) {
+ ((F_ISSET(ep, F_DEVSET) &&
+ (sb.st_dev != ep->mdev || sb.st_ino != ep->minode)) ||
+ timespeccmp(&sb.st_mtimespec, &ep->mtim, !=))) {
msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE) ?
"250|%s: file modified more recently than this copy; use ! to override" :
"251|%s: file modified more recently than this copy");
@@ -873,25 +880,10 @@ success_open:
SIGUNBLOCK;
/* Try and get a lock. */
- if (!noname && file_lock(sp, NULL, NULL, fd, 0) == LOCK_UNAVAIL)
+ if (!noname && file_lock(sp, NULL, fd, 0) == LOCK_UNAVAIL)
msgq_str(sp, M_ERR, name,
"252|%s: write lock was unavailable");
-#if __linux__
- /*
- * XXX
- * In libc 4.5.x, fdopen(fd, "w") clears the O_APPEND flag (if set).
- * This bug is fixed in libc 4.6.x.
- *
- * This code works around this problem for libc 4.5.x users.
- * Note that this code is harmless if you're using libc 4.6.x.
- */
- if (LF_ISSET(FS_APPEND) && lseek(fd, (off_t)0, SEEK_END) < 0) {
- msgq(sp, M_SYSERR, name);
- return (1);
- }
-#endif
-
/*
* Use stdio for buffering.
*
@@ -925,13 +917,13 @@ success_open:
*/
if (noname)
if (stat(name, &sb))
- time(&ep->mtime);
+ timepoint_system(&ep->mtim);
else {
F_SET(ep, F_DEVSET);
ep->mdev = sb.st_dev;
ep->minode = sb.st_ino;
- ep->mtime = sb.st_mtime;
+ ep->mtim = sb.st_mtimespec;
}
/*
@@ -1023,9 +1015,10 @@ success_open:
* recreate the file. So, let's not risk it.
*/
static int
-file_backup(sp, name, bname)
- SCR *sp;
- char *name, *bname;
+file_backup(
+ SCR *sp,
+ char *name,
+ char *bname)
{
struct dirent *dp;
struct stat sb;
@@ -1035,6 +1028,10 @@ file_backup(sp, name, bname)
size_t blen;
int flags, maxnum, nr, num, nw, rfd, wfd, version;
char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192];
+ CHAR_T *wp;
+ size_t wlen;
+ size_t nlen;
+ char *d = NULL;
rfd = wfd = -1;
bp = estr = wfname = NULL;
@@ -1064,15 +1061,20 @@ file_backup(sp, name, bname)
*
* Shell and file name expand the option's value.
*/
- argv_init(sp, &cmd);
- ex_cinit(&cmd, 0, 0, 0, 0, 0, NULL);
+ ex_cinit(sp, &cmd, 0, 0, 0, 0, 0);
if (bname[0] == 'N') {
version = 1;
++bname;
} else
version = 0;
- if (argv_exp2(sp, &cmd, bname, strlen(bname)))
+ CHAR2INT(sp, bname, strlen(bname), wp, wlen);
+ if ((wp = v_wstrdup(sp, wp, wlen)) == NULL)
+ return (1);
+ if (argv_exp2(sp, &cmd, wp, wlen)) {
+ free(wp);
return (1);
+ }
+ free(wp);
/*
* 0 args: impossible.
@@ -1095,9 +1097,13 @@ file_backup(sp, name, bname)
* by one.
*/
if (version) {
- GET_SPACE_GOTO(sp, bp, blen, cmd.argv[0]->len * 2 + 50);
- for (t = bp, slash = NULL,
- p = cmd.argv[0]->bp; p[0] != '\0'; *t++ = *p++)
+ GET_SPACE_GOTOC(sp, bp, blen, cmd.argv[0]->len * 2 + 50);
+ INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1,
+ p, nlen);
+ d = strdup(p);
+ p = d;
+ for (t = bp, slash = NULL;
+ p[0] != '\0'; *t++ = *p++)
if (p[0] == '%') {
if (p[1] != '%')
*t++ = '%';
@@ -1118,7 +1124,8 @@ file_backup(sp, name, bname)
p = slash + 1;
}
if (dirp == NULL) {
- estr = cmd.argv[0]->bp;
+ INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1,
+ estr, nlen);
goto err;
}
@@ -1132,7 +1139,8 @@ file_backup(sp, name, bname)
wfname = bp;
} else {
bp = NULL;
- wfname = cmd.argv[0]->bp;
+ INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1,
+ wfname, nlen);
}
/* Open the backup file, avoiding lurkers. */
@@ -1192,22 +1200,69 @@ err: if (rfd != -1)
}
if (estr)
msgq_str(sp, M_SYSERR, estr, "%s");
+ if (d != NULL)
+ free(d);
if (bp != NULL)
FREE_SPACE(sp, bp, blen);
return (1);
}
/*
+ * file_encinit --
+ * Read the first line and set the O_FILEENCODING.
+ */
+static void
+file_encinit(SCR *sp)
+{
+#if defined(USE_WIDECHAR) && defined(USE_ICONV)
+ size_t len;
+ char *p;
+ size_t blen = 0;
+ char buf[4096]; /* not need to be '\0'-terminated */
+ recno_t ln = 1;
+ EXF *ep;
+
+ ep = sp->ep;
+
+ while (!db_rget(sp, ln++, &p, &len)) {
+ if (blen + len > sizeof(buf))
+ len = sizeof(buf) - blen;
+ memcpy(buf + blen, p, len);
+ blen += len;
+ if (blen == sizeof(buf))
+ break;
+ else
+ buf[blen++] = '\n';
+ }
+
+ /*
+ * Detect UTF-8 and fallback to the locale/preset encoding.
+ *
+ * XXX
+ * A manually set O_FILEENCODING indicates the "fallback
+ * encoding", but UTF-8, which can be safely detected, is not
+ * inherited from the old screen.
+ */
+ if (looks_utf8(buf, blen) > 1)
+ o_set(sp, O_FILEENCODING, OS_STRDUP, "utf-8", 0);
+ else if (!O_ISSET(sp, O_FILEENCODING) ||
+ !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-8", 5))
+ o_set(sp, O_FILEENCODING, OS_STRDUP, codeset(), 0);
+
+ conv_enc(sp, O_FILEENCODING, 0);
+#endif
+}
+
+/*
* file_comment --
* Skip the first comment.
*/
static void
-file_comment(sp)
- SCR *sp;
+file_comment(SCR *sp)
{
recno_t lno;
size_t len;
- char *p;
+ CHAR_T *p;
for (lno = 1; !db_get(sp, lno, 0, &p, &len) && len == 0; ++lno);
if (p == NULL)
@@ -1250,9 +1305,10 @@ file_comment(sp)
* PUBLIC: int file_m1 __P((SCR *, int, int));
*/
int
-file_m1(sp, force, flags)
- SCR *sp;
- int force, flags;
+file_m1(
+ SCR *sp,
+ int force,
+ int flags)
{
EXF *ep;
@@ -1290,9 +1346,9 @@ file_m1(sp, force, flags)
* PUBLIC: int file_m2 __P((SCR *, int));
*/
int
-file_m2(sp, force)
- SCR *sp;
- int force;
+file_m2(
+ SCR *sp,
+ int force)
{
EXF *ep;
@@ -1322,9 +1378,9 @@ file_m2(sp, force)
* PUBLIC: int file_m3 __P((SCR *, int));
*/
int
-file_m3(sp, force)
- SCR *sp;
- int force;
+file_m3(
+ SCR *sp,
+ int force)
{
EXF *ep;
@@ -1358,9 +1414,9 @@ file_m3(sp, force)
* PUBLIC: int file_aw __P((SCR *, int));
*/
int
-file_aw(sp, flags)
- SCR *sp;
- int flags;
+file_aw(
+ SCR *sp,
+ int flags)
{
if (!F_ISSET(sp->ep, F_MODIFIED))
return (0);
@@ -1419,9 +1475,9 @@ file_aw(sp, flags)
* PUBLIC: void set_alt_name __P((SCR *, char *));
*/
void
-set_alt_name(sp, name)
- SCR *sp;
- char *name;
+set_alt_name(
+ SCR *sp,
+ char *name)
{
if (sp->alt_name != NULL)
free(sp->alt_name);
@@ -1435,35 +1491,18 @@ set_alt_name(sp, name)
* file_lock --
* Get an exclusive lock on a file.
*
- * XXX
- * The default locking is flock(2) style, not fcntl(2). The latter is
- * known to fail badly on some systems, and its only advantage is that
- * it occasionally works over NFS.
- *
- * Furthermore, the semantics of fcntl(2) are wrong. The problems are
- * two-fold: you can't close any file descriptor associated with the file
- * without losing all of the locks, and you can't get an exclusive lock
- * unless you have the file open for writing. Someone ought to be shot,
- * but it's probably too late, they may already have reproduced. To get
- * around these problems, nvi opens the files for writing when it can and
- * acquires a second file descriptor when it can't. The recovery files
- * are examples of the former, they're always opened for writing. The DB
- * files can't be opened for writing because the semantics of DB are that
- * files opened for writing are flushed back to disk when the DB session
- * is ended. So, in that case we have to acquire an extra file descriptor.
- *
- * PUBLIC: lockr_t file_lock __P((SCR *, char *, int *, int, int));
+ * PUBLIC: lockr_t file_lock __P((SCR *, char *, int, int));
*/
lockr_t
-file_lock(sp, name, fdp, fd, iswrite)
- SCR *sp;
- char *name;
- int *fdp, fd, iswrite;
+file_lock(
+ SCR *sp,
+ char *name,
+ int fd,
+ int iswrite)
{
if (!O_ISSET(sp, O_LOCKFILES))
return (LOCK_SUCCESS);
-#ifdef HAVE_LOCK_FLOCK /* Hurrah! We've got flock(2). */
/*
* !!!
* We need to distinguish a lock not being available for the file
@@ -1481,59 +1520,4 @@ file_lock(sp, name, fdp, fd, iswrite)
|| errno == EWOULDBLOCK
#endif
? LOCK_UNAVAIL : LOCK_FAILED);
-#endif
-#ifdef HAVE_LOCK_FCNTL /* Gag me. We've got fcntl(2). */
-{
- struct flock arg;
- int didopen, sverrno;
-
- arg.l_type = F_WRLCK;
- arg.l_whence = 0; /* SEEK_SET */
- arg.l_start = arg.l_len = 0;
- arg.l_pid = 0;
-
- /*
- * If the file descriptor isn't opened for writing, it must fail.
- * If we fail because we can't get a read/write file descriptor,
- * we return LOCK_SUCCESS, believing that the file is readonly
- * and that will be sufficient to warn the user.
- */
- if (!iswrite) {
- if (name == NULL || fdp == NULL)
- return (LOCK_FAILED);
- if ((fd = open(name, O_RDWR, 0)) == -1)
- return (LOCK_SUCCESS);
- *fdp = fd;
- didopen = 1;
- }
-
- errno = 0;
- if (!fcntl(fd, F_SETLK, &arg)) {
- fcntl(fd, F_SETFD, 1);
- return (LOCK_SUCCESS);
- }
-
- if (didopen) {
- sverrno = errno;
- (void)close(fd);
- errno = sverrno;
- }
-
- /*
- * !!!
- * We need to distinguish a lock not being available for the file
- * from the file system not supporting locking. Fcntl is documented
- * as returning EACCESS and EAGAIN; add EWOULDBLOCK for good measure,
- * and assume they are the former. There's no portable way to do this.
- */
- return (errno == EACCES || errno == EAGAIN
-#ifdef EWOULDBLOCK
- || errno == EWOULDBLOCK
-#endif
- ? LOCK_UNAVAIL : LOCK_FAILED);
-}
-#endif
-#if !defined(HAVE_LOCK_FLOCK) && !defined(HAVE_LOCK_FCNTL)
- return (LOCK_SUCCESS);
-#endif
}
OpenPOWER on IntegriCloud