summaryrefslogtreecommitdiff
path: root/src/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileio.c')
-rw-r--r--src/fileio.c212
1 files changed, 155 insertions, 57 deletions
diff --git a/src/fileio.c b/src/fileio.c
index f1cfe0eb625..5e9b36ee44a 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1,6 +1,6 @@
/* File IO for GNU Emacs.
-Copyright (C) 1985-1988, 1993-2012 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-2013 Free Software Foundation, Inc.
This file is part of GNU Emacs.
@@ -379,12 +379,26 @@ Given a Unix syntax file name, returns a string ending in slash. */)
strcat (res, "/");
beg = res;
p = beg + strlen (beg);
+ dostounix_filename (beg);
+ tem_fn = make_specified_string (beg, -1, p - beg,
+ STRING_MULTIBYTE (filename));
}
+ else
+ tem_fn = make_specified_string (beg - 2, -1, p - beg + 2,
+ STRING_MULTIBYTE (filename));
+ }
+ else if (STRING_MULTIBYTE (filename))
+ {
+ tem_fn = ENCODE_FILE (make_specified_string (beg, -1, p - beg, 1));
+ dostounix_filename (SSDATA (tem_fn));
+ tem_fn = DECODE_FILE (tem_fn);
+ }
+ else
+ {
+ dostounix_filename (beg);
+ tem_fn = make_specified_string (beg, -1, p - beg, 0);
}
- tem_fn = ENCODE_FILE (make_specified_string (beg, -1, p - beg,
- STRING_MULTIBYTE (filename)));
- dostounix_filename (SSDATA (tem_fn));
- return DECODE_FILE (tem_fn);
+ return tem_fn;
#else /* DOS_NT */
return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename));
#endif /* DOS_NT */
@@ -459,12 +473,14 @@ get a current directory to run processes in. */)
return Ffile_name_directory (filename);
}
-/* Convert from file name SRC of length SRCLEN to directory name
- in DST. On UNIX, just make sure there is a terminating /.
- Return the length of DST in bytes. */
+/* Convert from file name SRC of length SRCLEN to directory name in
+ DST. MULTIBYTE non-zero means the file name in SRC is a multibyte
+ string. On UNIX, just make sure there is a terminating /. Return
+ the length of DST in bytes. */
static ptrdiff_t
-file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen)
+file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen,
+ bool multibyte)
{
if (srclen == 0)
{
@@ -483,14 +499,17 @@ file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen)
srclen++;
}
#ifdef DOS_NT
- {
- Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
+ if (multibyte)
+ {
+ Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
- tem_fn = ENCODE_FILE (tem_fn);
- dostounix_filename (SSDATA (tem_fn));
- tem_fn = DECODE_FILE (tem_fn);
- memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
- }
+ tem_fn = ENCODE_FILE (tem_fn);
+ dostounix_filename (SSDATA (tem_fn));
+ tem_fn = DECODE_FILE (tem_fn);
+ memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
+ }
+ else
+ dostounix_filename (dst);
#endif
return srclen;
}
@@ -526,16 +545,18 @@ For a Unix-syntax file name, just appends a slash. */)
}
buf = alloca (SBYTES (file) + 10);
- length = file_name_as_directory (buf, SSDATA (file), SBYTES (file));
+ length = file_name_as_directory (buf, SSDATA (file), SBYTES (file),
+ STRING_MULTIBYTE (file));
return make_specified_string (buf, -1, length, STRING_MULTIBYTE (file));
}
-/* Convert from directory name SRC of length SRCLEN to
- file name in DST. On UNIX, just make sure there isn't
- a terminating /. Return the length of DST in bytes. */
+/* Convert from directory name SRC of length SRCLEN to file name in
+ DST. MULTIBYTE non-zero means the file name in SRC is a multibyte
+ string. On UNIX, just make sure there isn't a terminating /.
+ Return the length of DST in bytes. */
static ptrdiff_t
-directory_file_name (char *dst, char *src, ptrdiff_t srclen)
+directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte)
{
/* Process as Unix format: just remove any final slash.
But leave "/" unchanged; do not change it to "". */
@@ -551,14 +572,17 @@ directory_file_name (char *dst, char *src, ptrdiff_t srclen)
srclen--;
}
#ifdef DOS_NT
- {
- Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
+ if (multibyte)
+ {
+ Lisp_Object tem_fn = make_specified_string (dst, -1, srclen, 1);
- tem_fn = ENCODE_FILE (tem_fn);
- dostounix_filename (SSDATA (tem_fn));
- tem_fn = DECODE_FILE (tem_fn);
- memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
- }
+ tem_fn = ENCODE_FILE (tem_fn);
+ dostounix_filename (SSDATA (tem_fn));
+ tem_fn = DECODE_FILE (tem_fn);
+ memcpy (dst, SSDATA (tem_fn), (srclen = SBYTES (tem_fn)) + 1);
+ }
+ else
+ dostounix_filename (dst);
#endif
return srclen;
}
@@ -594,7 +618,8 @@ In Unix-syntax, this function just removes the final slash. */)
}
buf = alloca (SBYTES (directory) + 20);
- length = directory_file_name (buf, SSDATA (directory), SBYTES (directory));
+ length = directory_file_name (buf, SSDATA (directory), SBYTES (directory),
+ STRING_MULTIBYTE (directory));
return make_specified_string (buf, -1, length, STRING_MULTIBYTE (directory));
}
@@ -1044,7 +1069,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
/* `egetenv' may return a unibyte string, which will bite us since
we expect the directory to be multibyte. */
tem = build_string (newdir);
- if (!STRING_MULTIBYTE (tem))
+ if (multibyte && !STRING_MULTIBYTE (tem))
{
hdir = DECODE_FILE (tem);
newdir = SSDATA (hdir);
@@ -1066,7 +1091,18 @@ filesystem tree, not (expand-file-name ".." dirname). */)
unblock_input ();
if (pw)
{
+ Lisp_Object tem;
+
newdir = pw->pw_dir;
+ /* `getpwnam' may return a unibyte string, which will
+ bite us since we expect the directory to be
+ multibyte. */
+ tem = build_string (newdir);
+ if (multibyte && !STRING_MULTIBYTE (tem))
+ {
+ hdir = DECODE_FILE (tem);
+ newdir = SSDATA (hdir);
+ }
nm = p;
#ifdef DOS_NT
collapse_newdir = 0;
@@ -1090,6 +1126,13 @@ filesystem tree, not (expand-file-name ".." dirname). */)
adir = alloca (MAXPATHLEN + 1);
if (!getdefdir (c_toupper (drive) - 'A' + 1, adir))
adir = NULL;
+ else if (multibyte)
+ {
+ Lisp_Object tem = build_string (adir);
+
+ tem = DECODE_FILE (tem);
+ memcpy (adir, SSDATA (tem), SBYTES (tem) + 1);
+ }
}
if (!adir)
{
@@ -1148,6 +1191,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
indirectly by prepending newdir to nm if necessary, and using
cwd (or the wd of newdir's drive) as the new newdir. */
char *adir;
+
if (IS_DRIVE (newdir[0]) && IS_DEVICE_SEP (newdir[1]))
{
drive = (unsigned char) newdir[0];
@@ -1157,7 +1201,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
{
ptrdiff_t newlen = strlen (newdir);
char *tmp = alloca (newlen + strlen (nm) + 2);
- file_name_as_directory (tmp, newdir, newlen);
+ file_name_as_directory (tmp, newdir, newlen, multibyte);
strcat (tmp, nm);
nm = tmp;
}
@@ -1165,10 +1209,17 @@ filesystem tree, not (expand-file-name ".." dirname). */)
if (drive)
{
if (!getdefdir (c_toupper (drive) - 'A' + 1, adir))
- newdir = "/";
+ strcpy (adir, "/");
}
else
getcwd (adir, MAXPATHLEN + 1);
+ if (multibyte)
+ {
+ Lisp_Object tem = build_string (adir);
+
+ tem = DECODE_FILE (tem);
+ memcpy (adir, SSDATA (tem), SBYTES (tem) + 1);
+ }
newdir = adir;
}
@@ -1255,7 +1306,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
strcpy (target, newdir);
}
else
- file_name_as_directory (target, newdir, length);
+ file_name_as_directory (target, newdir, length, multibyte);
}
strcat (target, nm);
@@ -1341,9 +1392,14 @@ filesystem tree, not (expand-file-name ".." dirname). */)
target[1] = ':';
}
result = make_specified_string (target, -1, o - target, multibyte);
- result = ENCODE_FILE (result);
- dostounix_filename (SSDATA (result));
- result = DECODE_FILE (result);
+ if (multibyte)
+ {
+ result = ENCODE_FILE (result);
+ dostounix_filename (SSDATA (result));
+ result = DECODE_FILE (result);
+ }
+ else
+ dostounix_filename (SSDATA (result));
#else /* !DOS_NT */
result = make_specified_string (target, -1, o - target, multibyte);
#endif /* !DOS_NT */
@@ -1625,18 +1681,24 @@ those `/' is discarded. */)
memcpy (nm, SDATA (filename), SBYTES (filename) + 1);
#ifdef DOS_NT
- {
- Lisp_Object encoded_filename = ENCODE_FILE (filename);
- Lisp_Object tem_fn;
-
- dostounix_filename (SDATA (encoded_filename));
- tem_fn = DECODE_FILE (encoded_filename);
- nm = alloca (SBYTES (tem_fn) + 1);
- memcpy (nm, SDATA (tem_fn), SBYTES (tem_fn) + 1);
- substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
- if (substituted)
- filename = tem_fn;
- }
+ if (multibyte)
+ {
+ Lisp_Object encoded_filename = ENCODE_FILE (filename);
+ Lisp_Object tem_fn;
+
+ dostounix_filename (SDATA (encoded_filename));
+ tem_fn = DECODE_FILE (encoded_filename);
+ nm = alloca (SBYTES (tem_fn) + 1);
+ memcpy (nm, SDATA (tem_fn), SBYTES (tem_fn) + 1);
+ substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
+ if (substituted)
+ filename = tem_fn;
+ }
+ else
+ {
+ dostounix_filename (nm);
+ substituted = (memcmp (nm, SDATA (filename), SBYTES (filename)) != 0);
+ }
#endif
endp = nm + SBYTES (filename);
@@ -1956,10 +2018,26 @@ entries (depending on how Emacs was built). */)
out_st.st_mode = 0;
#ifdef WINDOWSNT
+ if (!NILP (preserve_extended_attributes))
+ {
+#ifdef HAVE_POSIX_ACL
+ acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS);
+ if (acl == NULL && errno != ENOTSUP)
+ report_file_error ("Getting ACL", Fcons (file, Qnil));
+#endif
+ }
if (!CopyFile (SDATA (encoded_file),
SDATA (encoded_newname),
FALSE))
- report_file_error ("Copying file", Fcons (file, Fcons (newname, Qnil)));
+ {
+ /* CopyFile doesn't set errno when it fails. By far the most
+ "popular" reason is that the target is read-only. */
+ if (GetLastError () == 5)
+ errno = EACCES;
+ else
+ errno = EPERM;
+ report_file_error ("Copying file", Fcons (file, Fcons (newname, Qnil)));
+ }
/* CopyFile retains the timestamp by default. */
else if (NILP (keep_time))
{
@@ -1983,6 +2061,17 @@ entries (depending on how Emacs was built). */)
/* Restore original attributes. */
SetFileAttributes (filename, attributes);
}
+#ifdef HAVE_POSIX_ACL
+ if (acl != NULL)
+ {
+ bool fail =
+ acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0;
+ if (fail && errno != ENOTSUP)
+ report_file_error ("Setting ACL", Fcons (newname, Qnil));
+
+ acl_free (acl);
+ }
+#endif
#else /* not WINDOWSNT */
immediate_quit = 1;
ifd = emacs_open (SSDATA (encoded_file), O_RDONLY, 0);
@@ -2915,8 +3004,10 @@ DEFUN ("set-file-selinux-context", Fset_file_selinux_context,
CONTEXT should be a list (USER ROLE TYPE RANGE), where the list
elements are strings naming the components of a SELinux context.
-This function does nothing if SELinux is disabled, or if Emacs was not
-compiled with SELinux support. */)
+Value is t if setting of SELinux context was successful, nil otherwise.
+
+This function does nothing and returns nil if SELinux is disabled,
+or if Emacs was not compiled with SELinux support. */)
(Lisp_Object filename, Lisp_Object context)
{
Lisp_Object absname;
@@ -2982,6 +3073,7 @@ compiled with SELinux support. */)
context_free (parsed_con);
freecon (con);
+ return fail ? Qnil : Qt;
}
else
report_file_error ("Doing lgetfilecon", Fcons (absname, Qnil));
@@ -2992,11 +3084,11 @@ compiled with SELinux support. */)
}
DEFUN ("file-acl", Ffile_acl, Sfile_acl, 1, 1, 0,
- doc: /* Return ACL entries of file named FILENAME, as a string.
+ doc: /* Return ACL entries of file named FILENAME.
+The entries are returned in a format suitable for use in `set-file-acl'
+but is otherwise undocumented and subject to change.
Return nil if file does not exist or is not accessible, or if Emacs
-was unable to determine the ACL entries. The latter can happen for
-local files if Emacs was not compiled with ACL support, or for remote
-files if the file handler returns nil for the file's ACL entries. */)
+was unable to determine the ACL entries. */)
(Lisp_Object filename)
{
Lisp_Object absname;
@@ -3046,6 +3138,8 @@ DEFUN ("set-file-acl", Fset_file_acl, Sset_file_acl,
ACL-STRING should contain the textual representation of the ACL
entries in a format suitable for the platform.
+Value is t if setting of ACL was successful, nil otherwise.
+
Setting ACL for local files requires Emacs to be built with ACL
support. */)
(Lisp_Object filename, Lisp_Object acl_string)
@@ -3085,6 +3179,7 @@ support. */)
report_file_error ("Setting ACL", Fcons (absname, Qnil));
acl_free (acl);
+ return fail ? Qnil : Qt;
}
#endif
@@ -3398,7 +3493,10 @@ the number of characters that replace previous buffer contents.
This function does code conversion according to the value of
`coding-system-for-read' or `file-coding-system-alist', and sets the
-variable `last-coding-system-used' to the coding system actually used. */)
+variable `last-coding-system-used' to the coding system actually used.
+
+In addition, this function decodes the inserted text from known formats
+by calling `format-decode', which see. */)
(Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace)
{
struct stat st;
@@ -4112,7 +4210,7 @@ variable `last-coding-system-used' to the coding system actually used. */)
prepare_to_modify_buffer (GPT, GPT, NULL);
}
- move_gap (PT);
+ move_gap_both (PT, PT_BYTE);
if (GAP_SIZE < total)
make_gap (total - GAP_SIZE);