Partially sync files.el from XEmacs 21.5 for wildcard support.
[sxemacs] / src / fileio.c
index ec8e1e9..4a15934 100644 (file)
@@ -35,6 +35,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 #ifdef FILE_CODING
 #include "mule/file-coding.h"
 #endif
+#include "ent/ent.h"
 
 #ifdef HAVE_LIBGEN_H           /* Must come before sysfile.h */
 #include <libgen.h>
@@ -448,7 +449,7 @@ Bytecount file_basename_match_extension(Lisp_Object filename,
        Bytecount match = -1;
        Bytecount len = XSTRING_LENGTH( extension );
        if ( len > 0 ) {
-               char     re[len+6], 
+               char     re[len+6],
                        *rep = re;
                Bufbyte *ext = XSTRING_DATA(extension);
                Lisp_Object regexp;
@@ -465,7 +466,7 @@ Bytecount file_basename_match_extension(Lisp_Object filename,
                   terminator if need to append...
                */
                rep += len-1;
-               if ( *rep++ != '$' ) 
+               if ( *rep++ != '$' )
                        *rep++ = '$';
                *rep = '\0';
                regexp = make_string( (Bufbyte*)re, strlen(re));
@@ -519,7 +520,7 @@ It ignores trailing slash.
        res = make_string(p, end - p);
        if ( STRINGP( extension ) ) {
                Bytecount match;
-               match = file_basename_match_extension(res, 
+               match = file_basename_match_extension(res,
                                                      extension);
                if ( match >= 0 )
                        RETURN_UNGCPRO(make_string(p, match));
@@ -528,7 +529,7 @@ It ignores trailing slash.
                do {
                        ext = XCAR(rest);
                        Bytecount match;
-                       match = file_basename_match_extension(res, 
+                       match = file_basename_match_extension(res,
                                                              ext);
                        if ( match >= 0 )
                                RETURN_UNGCPRO(make_string(p, match));
@@ -601,17 +602,18 @@ get a current directory to run processes in.
        return Ffile_name_directory(filename);
 }
 \f
-static char *file_name_as_directory(char *out, char *in)
+static char *file_name_as_directory(char *out, const char *in, size_t len)
 {
        /* This function cannot GC */
        int size = strlen(in);
 
        if (size == 0) {
+               assert(len >= 3);
                out[0] = '.';
                out[1] = DIRECTORY_SEP;
                out[2] = '\0';
        } else {
-               strcpy(out, in);
+               xstrncpy(out, in, len);
                /* Append a slash if necessary */
                if (!IS_ANY_SEP(out[size - 1])) {
                        out[size] = DIRECTORY_SEP;
@@ -633,8 +635,9 @@ except for (file-name-as-directory \"\") => \"./\".
       (filename))
 {
        /* This function can GC.  GC checked 2000-07-28 ben */
-       char *buf;
-       Lisp_Object handler;
+       size_t len = 0;
+       char *buf = NULL;
+       Lisp_Object handler = Qnil;
 
        CHECK_STRING(filename);
 
@@ -645,9 +648,10 @@ except for (file-name-as-directory \"\") => \"./\".
                return call2_check_string(handler, Qfile_name_as_directory,
                                          filename);
 
-       buf = (char *)alloca(XSTRING_LENGTH(filename) + 10);
+       len = XSTRING_LENGTH(filename) + 10;
+       buf = (char *)alloca(len);
        return build_string(file_name_as_directory
-                           (buf, (char *)XSTRING_DATA(filename)));
+                           (buf, (char*)XSTRING_DATA(filename), len));
 }
 \f
 /*
@@ -657,13 +661,13 @@ except for (file-name-as-directory \"\") => \"./\".
  * Value is nonzero if the string output is different from the input.
  */
 
-static int directory_file_name(const char *src, char *dst)
+static int directory_file_name(const char *src, char *dst, size_t len)
 {
        /* This function cannot GC */
        long slen = strlen(src);
        /* Process as Unix format: just remove any final slash.
           But leave "/" unchanged; do not change it to "".  */
-       strcpy(dst, src);
+       xstrncpy(dst, src, len);
        if (slen > 1 && IS_DIRECTORY_SEP(dst[slen - 1])
            )
                dst[slen - 1] = 0;
@@ -680,7 +684,8 @@ In Unix-syntax, this function just removes the final slash.
       (directory))
 {
        /* This function can GC.  GC checked 2000-07-28 ben */
-       char *buf;
+       size_t len = 0;
+       char *buf = NULL;
        Lisp_Object handler;
 
        CHECK_STRING(directory);
@@ -696,8 +701,9 @@ In Unix-syntax, this function just removes the final slash.
        if (!NILP(handler))
                return call2_check_string(handler, Qdirectory_file_name,
                                          directory);
-       buf = (char *)alloca(XSTRING_LENGTH(directory) + 20);
-       directory_file_name((char *)XSTRING_DATA(directory), buf);
+       len = XSTRING_LENGTH(directory) + 20;
+       buf = (char *)alloca(len);
+       directory_file_name((char *)XSTRING_DATA(directory), buf, len);
        return build_string(buf);
 }
 \f
@@ -1024,12 +1030,12 @@ See also the function `substitute-in-file-name'.
 
        if (newdir) {
                if (nm[0] == 0 || IS_DIRECTORY_SEP(nm[0]))
-                       strcpy((char *)target, (char *)newdir);
+                       xstrncpy((char *)target, (char *)newdir, tlen);
                else
-                       file_name_as_directory((char *)target, (char *)newdir);
+                       file_name_as_directory((char *)target, (char *)newdir, tlen);
        }
 
-       strcat((char *)target, (char *)nm);
+       xstrncat((char *)target, (char *)nm, tlen-1);
 
        /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */
 
@@ -1092,58 +1098,66 @@ in the realpath() function.
 
        {
                Lisp_Object handler =
-                   Ffind_file_name_handler(expanded_name, Qfile_truename);
+                       Ffind_file_name_handler(expanded_name, Qfile_truename);
 
                if (!NILP(handler))
                        RETURN_UNGCPRO
-                           (call2_check_string
-                            (handler, Qfile_truename, expanded_name));
+                               (call2_check_string
+                                (handler, Qfile_truename, expanded_name));
        }
 
        {
                char resolved_path[MAXPATHLEN];
-               Extbyte *path;
-               Extbyte *p;
+               Extbyte *path = NULL;
+               Extbyte *p = NULL;
                Extcount elen;
 
                TO_EXTERNAL_FORMAT(LISP_STRING, expanded_name,
                                   ALLOCA, (path, elen), Qfile_name);
-
                p = path;
 
                if (elen > MAXPATHLEN)
                        goto toolong;
 
                /* Try doing it all at once. */
-               /* !! Does realpath() Mule-encapsulate?
-                  Answer: Nope! So we do it above */
-               if (!xrealpath((char *)path, resolved_path)) {
-                       /* Didn't resolve it -- have to do it one component at a time. */
-                       /* "realpath" is a typically useless, stupid un*x piece of crap.
-                          It claims to return a useful value in the "error" case, but since
-                          there is no indication provided of how far along the pathname
-                          the function went before erring, there is no way to use the
-                          partial result returned.  What a piece of junk.
-
-                          The above comment refers to historical versions of
-                          realpath().  The Unix98 specs state:
-
-                          "On successful completion, realpath() returns a
-                          pointer to the resolved name. Otherwise, realpath()
-                          returns a null pointer and sets errno to indicate the
-                          error, and the contents of the buffer pointed to by
-                          resolved_name are undefined."
-
-                          Since we depend on undocumented semantics of various system realpath()s,
-                          we just use our own version in realpath.c. */
+               /* !! Does realpath() Mule-encapsulate?  Answer: Nope!
+                  So we do it above */
+               if (path != NULL && !xrealpath((char *)path, resolved_path)) {
+                       /* Didn't resolve it -- have to do it one
+                          component at a time.
+
+                          "realpath" is a typically useless, stupid
+                          un*x piece of crap.  It claims to return a
+                          useful value in the "error" case, but since
+                          there is no indication provided of how far
+                          along the pathname the function went before
+                          erring, there is no way to use the partial
+                          result returned.  What a piece of junk.
+
+                          The above comment refers to historical
+                          versions of realpath().  The Unix98 specs
+                          state:
+
+                          "On successful completion, realpath()
+                          returns a pointer to the resolved
+                          name. Otherwise, realpath() returns a null
+                          pointer and sets errno to indicate the
+                          error, and the contents of the buffer
+                          pointed to by resolved_name are undefined."
+
+                          Since we depend on undocumented semantics
+                          of various system realpath()s, we just use
+                          our own version in realpath.c.
+                       */
                        for (;;) {
-                               Extbyte *pos;
+                               Extbyte *pos = NULL;
 
-                               for (pos = p + 1; pos < path + elen; pos++)
+                               for (pos = p + 1; pos < path + elen; pos++) {
                                        if (IS_DIRECTORY_SEP(*pos)) {
                                                *(p = pos) = 0;
                                                break;
                                        }
+                               }
                                if (p != pos)
                                        p = 0;
 
@@ -1154,32 +1168,37 @@ in the realpath() function.
                                                break;
 
                                } else if (errno == ENOENT || errno == EACCES) {
-                                       /* Failed on this component.  Just tack on the rest of
-                                          the string and we are done. */
+                                       /* Failed on this component.
+                                          Just tack on the rest of
+                                          the string and we are
+                                          done. */
                                        int rlen = strlen(resolved_path);
 
-                                       /* "On failure, it returns NULL, sets errno to indicate
-                                          the error, and places in resolved_path the absolute pathname
-                                          of the path component which could not be resolved." */
-
-                                       if (p) {
-                                               int plen = elen - (p - path);
+                                       /* "On failure, it returns
+                                          NULL, sets errno to
+                                          indicate the error, and
+                                          places in resolved_path the
+                                          absolute pathname of the
+                                          path component which could
+                                          not be resolved."
+                                       */
+                                       if (p == NULL ) {
+                                               break;
+                                       }
+                                       int plen = elen - (p - path);
 
-                                               if (rlen > 1
-                                                   &&
-                                                   IS_DIRECTORY_SEP
-                                                   (resolved_path[rlen - 1]))
-                                                       rlen = rlen - 1;
+                                       if (rlen > 1 &&
+                                           IS_DIRECTORY_SEP
+                                           (resolved_path[rlen - 1]))
+                                               rlen = rlen - 1;
 
-                                               if (plen + rlen + 1 >
-                                                   countof(resolved_path))
-                                                       goto toolong;
+                                       if ((plen + rlen + 1) >
+                                           countof(resolved_path))
+                                               goto toolong;
 
-                                               resolved_path[rlen] =
-                                                   DIRECTORY_SEP;
-                                               memcpy(resolved_path + rlen + 1,
-                                                      p + 1, plen + 1 - 1);
-                                       }
+                                       resolved_path[rlen] = DIRECTORY_SEP;
+                                       memcpy(resolved_path + rlen + 1,
+                                              p + 1, plen + 1 - 1);
                                        break;
                                } else
                                        goto lose;
@@ -1189,13 +1208,12 @@ in the realpath() function.
                {
                        Lisp_Object resolved_name;
                        int rlen = strlen(resolved_path);
+
                        if (elen > 0
-                           &&
-                           IS_DIRECTORY_SEP(XSTRING_BYTE
-                                            (expanded_name, elen - 1))
-                           && !(rlen > 0
-                                && IS_DIRECTORY_SEP(resolved_path[rlen - 1])))
-                       {
+                           && IS_DIRECTORY_SEP(
+                                   XSTRING_BYTE(expanded_name, elen-1))
+                           && !(rlen > 0 &&
+                                IS_DIRECTORY_SEP(resolved_path[rlen-1]))) {
                                if (rlen + 1 > countof(resolved_path))
                                        goto toolong;
                                resolved_path[rlen++] = DIRECTORY_SEP;
@@ -1207,10 +1225,10 @@ in the realpath() function.
                        RETURN_UNGCPRO(resolved_name);
                }
 
-             toolong:
+       toolong:
                errno = ENAMETOOLONG;
                goto lose;
-             lose:
+       lose:
                report_file_error("Finding truename", list1(expanded_name));
        }
        RETURN_UNGCPRO(Qnil);
@@ -1233,6 +1251,7 @@ If `/~' appears, all of FILENAME through that `/' is discarded.
        Bufbyte *target = 0;
        int total = 0;
        int substituted = 0;
+       size_t avail = 0;
        Bufbyte *xnm;
        Lisp_Object handler;
 
@@ -1309,19 +1328,22 @@ If `/~' appears, all of FILENAME through that `/' is discarded.
 
        /* If substitution required, recopy the filename and do it */
        /* Make space in stack frame for the new copy */
-       xnm = (Bufbyte *) alloca(XSTRING_LENGTH(filename) + total + 1);
+       avail = XSTRING_LENGTH(filename) + total + 1;
+       xnm = (Bufbyte *) alloca(avail);
        x = xnm;
 
        /* Copy the rest of the name through, replacing $ constructs with values */
        for (p = nm; *p;)
-               if (*p != '$')
+               if (*p != '$') {
                        *x++ = *p++;
-               else {
+                       avail--;
+               } else {
                        p++;
                        if (p == endp)
                                goto badsubst;
                        else if (*p == '$') {
                                *x++ = *p++;
+                               avail--;
                                continue;
                        } else if (*p == '{') {
                                o = ++p;
@@ -1347,8 +1369,9 @@ If `/~' appears, all of FILENAME through that `/' is discarded.
                        if (!o)
                                goto badvar;
 
-                       strcpy((char *)x, (char *)o);
+                       xstrncpy((char *)x, (char *)o, avail);
                        x += strlen((char *)o);
+                       avail -= strlen((char *)o);
                }
 
        *x = 0;
@@ -1522,6 +1545,7 @@ A prefix arg makes KEEP-TIME non-nil.
                                 O_RDONLY | OPEN_BINARY, 0);
        if (ifd < 0) {
                report_file_error("Opening input file", list1(filename));
+               goto end;
        }
        record_unwind_protect(close_file_unwind, make_int(ifd));
 
@@ -1568,6 +1592,8 @@ A prefix arg makes KEEP-TIME non-nil.
                                report_file_error("I/O error", list1(newname));
                }
 
+               if(close(ifd) <0)
+                       report_file_error("I/O error", list1(filename));
                /* Closing the output clobbers the file times on some systems.  */
                if (close(ofd) < 0)
                        report_file_error("I/O error", list1(newname));
@@ -1592,6 +1618,7 @@ A prefix arg makes KEEP-TIME non-nil.
                unbind_to(speccount, Qnil);
        }
 
+end:
        UNGCPRO;
        return Qnil;
 }
@@ -1624,9 +1651,9 @@ Create a directory.  One argument, a file name string.
        }
        strncpy(dir, (char *)XSTRING_DATA(dirname_),
                XSTRING_LENGTH(dirname_) + 1);
-        dir[XSTRING_LENGTH(dirname_)]='\0';
+       dir[XSTRING_LENGTH(dirname_)]='\0';
        if (dir[XSTRING_LENGTH(dirname_) - 1] == '/')
-                dir[XSTRING_LENGTH(dirname_) - 1] = '\0';
+               dir[XSTRING_LENGTH(dirname_) - 1] = '\0';
 
        if (mkdir(dir, 0777) != 0)
                report_file_error("Creating directory", list1(dirname_));
@@ -2826,7 +2853,7 @@ here because write-region handler writers need to be aware of it.
 {
        /* This function can call lisp.  GC checked 2000-07-28 ben */
        int desc;
-       int failure;
+       int failure, stat_res;
        int save_errno = 0;
        struct stat st;
        Lisp_Object fn = Qnil;
@@ -3045,7 +3072,7 @@ here because write-region handler writers need to be aware of it.
                NNUNGCPRO;
        }
 
-       sxemacs_stat((char *)XSTRING_DATA(fn), &st);
+       stat_res = sxemacs_stat((char *)XSTRING_DATA(fn), &st);
 
 #ifdef CLASH_DETECTION
        if (!auto_saving)
@@ -3056,7 +3083,13 @@ here because write-region handler writers need to be aware of it.
           to avoid a "file has changed on disk" warning on
           next attempt to save.  */
        if (visiting)
+          if (stat_res == 0)
                current_buffer->modtime = st.st_mtime;
+          /* else:
+               If sxemacs_stat failed, we have bigger problems, and
+                  most likely the file is gone, so the error next time is
+                  the right behavior
+           */
 
        if (failure) {
                errno = save_errno;
@@ -3696,6 +3729,9 @@ Non-nil second argument means save only current buffer.
        if (listdesc < 0 && !auto_saved && STRINGP(listfile))
                unlink((char *)XSTRING_DATA(listfile));
 
+       if (listdesc >= 0)
+               close(listdesc);
+
        /* Show "...done" only if the echo area would otherwise be empty. */
        if (auto_saved && NILP(no_message)
            && NILP(clear_echo_area(selected_frame(), Qauto_saving, 0))) {