diff options
Diffstat (limited to 'src/fileio.c')
| -rw-r--r-- | src/fileio.c | 264 |
1 files changed, 142 insertions, 122 deletions
diff --git a/src/fileio.c b/src/fileio.c index 59e84053773..0e6113f349d 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -233,7 +233,7 @@ void | |||
| 233 | restore_point_unwind (Lisp_Object location) | 233 | restore_point_unwind (Lisp_Object location) |
| 234 | { | 234 | { |
| 235 | Fgoto_char (location); | 235 | Fgoto_char (location); |
| 236 | Fset_marker (location, Qnil, Qnil); | 236 | unchain_marker (XMARKER (location)); |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | 239 | ||
| @@ -366,8 +366,7 @@ Given a Unix syntax file name, returns a string ending in slash. */) | |||
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | #ifdef DOS_NT | 368 | #ifdef DOS_NT |
| 369 | beg = alloca (SBYTES (filename) + 1); | 369 | beg = xlispstrdupa (filename); |
| 370 | memcpy (beg, SSDATA (filename), SBYTES (filename) + 1); | ||
| 371 | #else | 370 | #else |
| 372 | beg = SSDATA (filename); | 371 | beg = SSDATA (filename); |
| 373 | #endif | 372 | #endif |
| @@ -505,6 +504,10 @@ get a current directory to run processes in. */) | |||
| 505 | return Ffile_name_directory (filename); | 504 | return Ffile_name_directory (filename); |
| 506 | } | 505 | } |
| 507 | 506 | ||
| 507 | /* Maximum number of bytes that DST will be longer than SRC | ||
| 508 | in file_name_as_directory. This occurs when SRCLEN == 0. */ | ||
| 509 | enum { file_name_as_directory_slop = 2 }; | ||
| 510 | |||
| 508 | /* Convert from file name SRC of length SRCLEN to directory name in | 511 | /* Convert from file name SRC of length SRCLEN to directory name in |
| 509 | DST. MULTIBYTE non-zero means the file name in SRC is a multibyte | 512 | DST. MULTIBYTE non-zero means the file name in SRC is a multibyte |
| 510 | string. On UNIX, just make sure there is a terminating /. Return | 513 | string. On UNIX, just make sure there is a terminating /. Return |
| @@ -522,14 +525,10 @@ file_name_as_directory (char *dst, const char *src, ptrdiff_t srclen, | |||
| 522 | return 2; | 525 | return 2; |
| 523 | } | 526 | } |
| 524 | 527 | ||
| 525 | strcpy (dst, src); | 528 | memcpy (dst, src, srclen); |
| 526 | |||
| 527 | if (!IS_DIRECTORY_SEP (dst[srclen - 1])) | 529 | if (!IS_DIRECTORY_SEP (dst[srclen - 1])) |
| 528 | { | 530 | dst[srclen++] = DIRECTORY_SEP; |
| 529 | dst[srclen] = DIRECTORY_SEP; | 531 | dst[srclen] = 0; |
| 530 | dst[srclen + 1] = '\0'; | ||
| 531 | srclen++; | ||
| 532 | } | ||
| 533 | #ifdef DOS_NT | 532 | #ifdef DOS_NT |
| 534 | dostounix_filename (dst, multibyte); | 533 | dostounix_filename (dst, multibyte); |
| 535 | #endif | 534 | #endif |
| @@ -548,7 +547,8 @@ For a Unix-syntax file name, just appends a slash. */) | |||
| 548 | { | 547 | { |
| 549 | char *buf; | 548 | char *buf; |
| 550 | ptrdiff_t length; | 549 | ptrdiff_t length; |
| 551 | Lisp_Object handler; | 550 | Lisp_Object handler, val; |
| 551 | USE_SAFE_ALLOCA; | ||
| 552 | 552 | ||
| 553 | CHECK_STRING (file); | 553 | CHECK_STRING (file); |
| 554 | if (NILP (file)) | 554 | if (NILP (file)) |
| @@ -570,10 +570,12 @@ For a Unix-syntax file name, just appends a slash. */) | |||
| 570 | if (!NILP (Vw32_downcase_file_names)) | 570 | if (!NILP (Vw32_downcase_file_names)) |
| 571 | file = Fdowncase (file); | 571 | file = Fdowncase (file); |
| 572 | #endif | 572 | #endif |
| 573 | buf = alloca (SBYTES (file) + 10); | 573 | buf = SAFE_ALLOCA (SBYTES (file) + file_name_as_directory_slop + 1); |
| 574 | length = file_name_as_directory (buf, SSDATA (file), SBYTES (file), | 574 | length = file_name_as_directory (buf, SSDATA (file), SBYTES (file), |
| 575 | STRING_MULTIBYTE (file)); | 575 | STRING_MULTIBYTE (file)); |
| 576 | return make_specified_string (buf, -1, length, STRING_MULTIBYTE (file)); | 576 | val = make_specified_string (buf, -1, length, STRING_MULTIBYTE (file)); |
| 577 | SAFE_FREE (); | ||
| 578 | return val; | ||
| 577 | } | 579 | } |
| 578 | 580 | ||
| 579 | /* Convert from directory name SRC of length SRCLEN to file name in | 581 | /* Convert from directory name SRC of length SRCLEN to file name in |
| @@ -585,18 +587,17 @@ static ptrdiff_t | |||
| 585 | directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte) | 587 | directory_file_name (char *dst, char *src, ptrdiff_t srclen, bool multibyte) |
| 586 | { | 588 | { |
| 587 | /* Process as Unix format: just remove any final slash. | 589 | /* Process as Unix format: just remove any final slash. |
| 588 | But leave "/" unchanged; do not change it to "". */ | 590 | But leave "/" and "//" unchanged. */ |
| 589 | strcpy (dst, src); | 591 | while (srclen > 1 |
| 590 | if (srclen > 1 | ||
| 591 | && IS_DIRECTORY_SEP (dst[srclen - 1]) | ||
| 592 | #ifdef DOS_NT | 592 | #ifdef DOS_NT |
| 593 | && !IS_ANY_SEP (dst[srclen - 2]) | 593 | && !IS_ANY_SEP (src[srclen - 2]) |
| 594 | #endif | 594 | #endif |
| 595 | ) | 595 | && IS_DIRECTORY_SEP (src[srclen - 1]) |
| 596 | { | 596 | && ! (srclen == 2 && IS_DIRECTORY_SEP (src[0]))) |
| 597 | dst[srclen - 1] = 0; | 597 | srclen--; |
| 598 | srclen--; | 598 | |
| 599 | } | 599 | memcpy (dst, src, srclen); |
| 600 | dst[srclen] = 0; | ||
| 600 | #ifdef DOS_NT | 601 | #ifdef DOS_NT |
| 601 | dostounix_filename (dst, multibyte); | 602 | dostounix_filename (dst, multibyte); |
| 602 | #endif | 603 | #endif |
| @@ -614,7 +615,8 @@ In Unix-syntax, this function just removes the final slash. */) | |||
| 614 | { | 615 | { |
| 615 | char *buf; | 616 | char *buf; |
| 616 | ptrdiff_t length; | 617 | ptrdiff_t length; |
| 617 | Lisp_Object handler; | 618 | Lisp_Object handler, val; |
| 619 | USE_SAFE_ALLOCA; | ||
| 618 | 620 | ||
| 619 | CHECK_STRING (directory); | 621 | CHECK_STRING (directory); |
| 620 | 622 | ||
| @@ -637,10 +639,12 @@ In Unix-syntax, this function just removes the final slash. */) | |||
| 637 | if (!NILP (Vw32_downcase_file_names)) | 639 | if (!NILP (Vw32_downcase_file_names)) |
| 638 | directory = Fdowncase (directory); | 640 | directory = Fdowncase (directory); |
| 639 | #endif | 641 | #endif |
| 640 | buf = alloca (SBYTES (directory) + 20); | 642 | buf = SAFE_ALLOCA (SBYTES (directory) + 1); |
| 641 | length = directory_file_name (buf, SSDATA (directory), SBYTES (directory), | 643 | length = directory_file_name (buf, SSDATA (directory), SBYTES (directory), |
| 642 | STRING_MULTIBYTE (directory)); | 644 | STRING_MULTIBYTE (directory)); |
| 643 | return make_specified_string (buf, -1, length, STRING_MULTIBYTE (directory)); | 645 | val = make_specified_string (buf, -1, length, STRING_MULTIBYTE (directory)); |
| 646 | SAFE_FREE (); | ||
| 647 | return val; | ||
| 644 | } | 648 | } |
| 645 | 649 | ||
| 646 | static const char make_temp_name_tbl[64] = | 650 | static const char make_temp_name_tbl[64] = |
| @@ -838,6 +842,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 838 | Lisp_Object handler, result, handled_name; | 842 | Lisp_Object handler, result, handled_name; |
| 839 | bool multibyte; | 843 | bool multibyte; |
| 840 | Lisp_Object hdir; | 844 | Lisp_Object hdir; |
| 845 | USE_SAFE_ALLOCA; | ||
| 841 | 846 | ||
| 842 | CHECK_STRING (name); | 847 | CHECK_STRING (name); |
| 843 | 848 | ||
| @@ -944,8 +949,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 944 | #endif | 949 | #endif |
| 945 | 950 | ||
| 946 | /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */ | 951 | /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */ |
| 947 | nm = alloca (SBYTES (name) + 1); | 952 | nm = xlispstrdupa (name); |
| 948 | memcpy (nm, SSDATA (name), SBYTES (name) + 1); | ||
| 949 | 953 | ||
| 950 | #ifdef DOS_NT | 954 | #ifdef DOS_NT |
| 951 | /* Note if special escape prefix is present, but remove for now. */ | 955 | /* Note if special escape prefix is present, but remove for now. */ |
| @@ -1013,11 +1017,11 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1013 | || (p[2] == '.' && (IS_DIRECTORY_SEP (p[3]) | 1017 | || (p[2] == '.' && (IS_DIRECTORY_SEP (p[3]) |
| 1014 | || p[3] == 0)))) | 1018 | || p[3] == 0)))) |
| 1015 | lose = 1; | 1019 | lose = 1; |
| 1016 | /* We want to replace multiple `/' in a row with a single | 1020 | /* Replace multiple slashes with a single one, except |
| 1017 | slash. */ | 1021 | leave leading "//" alone. */ |
| 1018 | else if (p > nm | 1022 | else if (IS_DIRECTORY_SEP (p[0]) |
| 1019 | && IS_DIRECTORY_SEP (p[0]) | 1023 | && IS_DIRECTORY_SEP (p[1]) |
| 1020 | && IS_DIRECTORY_SEP (p[1])) | 1024 | && (p != nm || IS_DIRECTORY_SEP (p[2]))) |
| 1021 | lose = 1; | 1025 | lose = 1; |
| 1022 | p++; | 1026 | p++; |
| 1023 | } | 1027 | } |
| @@ -1100,10 +1104,11 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1100 | else /* ~user/filename */ | 1104 | else /* ~user/filename */ |
| 1101 | { | 1105 | { |
| 1102 | char *o, *p; | 1106 | char *o, *p; |
| 1103 | for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)); p++); | 1107 | for (p = nm; *p && !IS_DIRECTORY_SEP (*p); p++) |
| 1104 | o = alloca (p - nm + 1); | 1108 | continue; |
| 1109 | o = SAFE_ALLOCA (p - nm + 1); | ||
| 1105 | memcpy (o, nm, p - nm); | 1110 | memcpy (o, nm, p - nm); |
| 1106 | o [p - nm] = 0; | 1111 | o[p - nm] = 0; |
| 1107 | 1112 | ||
| 1108 | block_input (); | 1113 | block_input (); |
| 1109 | pw = getpwnam (o + 1); | 1114 | pw = getpwnam (o + 1); |
| @@ -1219,7 +1224,8 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1219 | if (!IS_DIRECTORY_SEP (nm[0])) | 1224 | if (!IS_DIRECTORY_SEP (nm[0])) |
| 1220 | { | 1225 | { |
| 1221 | ptrdiff_t newlen = strlen (newdir); | 1226 | ptrdiff_t newlen = strlen (newdir); |
| 1222 | char *tmp = alloca (newlen + strlen (nm) + 2); | 1227 | char *tmp = alloca (newlen + file_name_as_directory_slop |
| 1228 | + strlen (nm) + 1); | ||
| 1223 | file_name_as_directory (tmp, newdir, newlen, multibyte); | 1229 | file_name_as_directory (tmp, newdir, newlen, multibyte); |
| 1224 | strcat (tmp, nm); | 1230 | strcat (tmp, nm); |
| 1225 | nm = tmp; | 1231 | nm = tmp; |
| @@ -1273,31 +1279,18 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1273 | 1279 | ||
| 1274 | if (newdir) | 1280 | if (newdir) |
| 1275 | { | 1281 | { |
| 1276 | /* Get rid of any slash at the end of newdir, unless newdir is | 1282 | /* Ignore any slash at the end of newdir, unless newdir is |
| 1277 | just / or // (an incomplete UNC name). */ | 1283 | just "/" or "//". */ |
| 1278 | length = strlen (newdir); | 1284 | length = strlen (newdir); |
| 1279 | tlen = length + 1; | 1285 | while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1]) |
| 1280 | if (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1]) | 1286 | && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0]))) |
| 1281 | #ifdef WINDOWSNT | 1287 | length--; |
| 1282 | && !(length == 2 && IS_DIRECTORY_SEP (newdir[0])) | ||
| 1283 | #endif | ||
| 1284 | ) | ||
| 1285 | { | ||
| 1286 | char *temp = alloca (length); | ||
| 1287 | memcpy (temp, newdir, length - 1); | ||
| 1288 | temp[length - 1] = 0; | ||
| 1289 | length--; | ||
| 1290 | newdir = temp; | ||
| 1291 | } | ||
| 1292 | } | 1288 | } |
| 1293 | else | 1289 | else |
| 1294 | { | 1290 | length = 0; |
| 1295 | length = 0; | ||
| 1296 | tlen = 0; | ||
| 1297 | } | ||
| 1298 | 1291 | ||
| 1299 | /* Now concatenate the directory and name to new space in the stack frame. */ | 1292 | /* Now concatenate the directory and name to new space in the stack frame. */ |
| 1300 | tlen += strlen (nm) + 1; | 1293 | tlen = length + file_name_as_directory_slop + strlen (nm) + 1; |
| 1301 | #ifdef DOS_NT | 1294 | #ifdef DOS_NT |
| 1302 | /* Reserve space for drive specifier and escape prefix, since either | 1295 | /* Reserve space for drive specifier and escape prefix, since either |
| 1303 | or both may need to be inserted. (The Microsoft x86 compiler | 1296 | or both may need to be inserted. (The Microsoft x86 compiler |
| @@ -1305,7 +1298,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1305 | target = alloca (tlen + 4); | 1298 | target = alloca (tlen + 4); |
| 1306 | target += 4; | 1299 | target += 4; |
| 1307 | #else /* not DOS_NT */ | 1300 | #else /* not DOS_NT */ |
| 1308 | target = alloca (tlen); | 1301 | target = SAFE_ALLOCA (tlen); |
| 1309 | #endif /* not DOS_NT */ | 1302 | #endif /* not DOS_NT */ |
| 1310 | *target = 0; | 1303 | *target = 0; |
| 1311 | 1304 | ||
| @@ -1322,7 +1315,10 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1322 | if (!(drive && nm[0] && IS_DIRECTORY_SEP (newdir[0]) | 1315 | if (!(drive && nm[0] && IS_DIRECTORY_SEP (newdir[0]) |
| 1323 | && newdir[1] == '\0')) | 1316 | && newdir[1] == '\0')) |
| 1324 | #endif | 1317 | #endif |
| 1325 | strcpy (target, newdir); | 1318 | { |
| 1319 | memcpy (target, newdir, length); | ||
| 1320 | target[length] = 0; | ||
| 1321 | } | ||
| 1326 | } | 1322 | } |
| 1327 | else | 1323 | else |
| 1328 | file_name_as_directory (target, newdir, length, multibyte); | 1324 | file_name_as_directory (target, newdir, length, multibyte); |
| @@ -1382,8 +1378,9 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1382 | ++o; | 1378 | ++o; |
| 1383 | p += 3; | 1379 | p += 3; |
| 1384 | } | 1380 | } |
| 1385 | else if (p > target && IS_DIRECTORY_SEP (p[1])) | 1381 | else if (IS_DIRECTORY_SEP (p[1]) |
| 1386 | /* Collapse multiple `/' in a row. */ | 1382 | && (p != target || IS_DIRECTORY_SEP (p[2]))) |
| 1383 | /* Collapse multiple "/", except leave leading "//" alone. */ | ||
| 1387 | p++; | 1384 | p++; |
| 1388 | else | 1385 | else |
| 1389 | { | 1386 | { |
| @@ -1431,11 +1428,12 @@ filesystem tree, not (expand-file-name ".." dirname). */) | |||
| 1431 | { | 1428 | { |
| 1432 | handled_name = call3 (handler, Qexpand_file_name, | 1429 | handled_name = call3 (handler, Qexpand_file_name, |
| 1433 | result, default_directory); | 1430 | result, default_directory); |
| 1434 | if (STRINGP (handled_name)) | 1431 | if (! STRINGP (handled_name)) |
| 1435 | return handled_name; | 1432 | error ("Invalid handler in `file-name-handler-alist'"); |
| 1436 | error ("Invalid handler in `file-name-handler-alist'"); | 1433 | result = handled_name; |
| 1437 | } | 1434 | } |
| 1438 | 1435 | ||
| 1436 | SAFE_FREE (); | ||
| 1439 | return result; | 1437 | return result; |
| 1440 | } | 1438 | } |
| 1441 | 1439 | ||
| @@ -1693,8 +1691,7 @@ those `/' is discarded. */) | |||
| 1693 | /* Always work on a copy of the string, in case GC happens during | 1691 | /* Always work on a copy of the string, in case GC happens during |
| 1694 | decode of environment variables, causing the original Lisp_String | 1692 | decode of environment variables, causing the original Lisp_String |
| 1695 | data to be relocated. */ | 1693 | data to be relocated. */ |
| 1696 | nm = alloca (SBYTES (filename) + 1); | 1694 | nm = xlispstrdupa (filename); |
| 1697 | memcpy (nm, SDATA (filename), SBYTES (filename) + 1); | ||
| 1698 | 1695 | ||
| 1699 | #ifdef DOS_NT | 1696 | #ifdef DOS_NT |
| 1700 | dostounix_filename (nm, multibyte); | 1697 | dostounix_filename (nm, multibyte); |
| @@ -2048,7 +2045,7 @@ entries (depending on how Emacs was built). */) | |||
| 2048 | /* CopyFile retains the timestamp by default. */ | 2045 | /* CopyFile retains the timestamp by default. */ |
| 2049 | else if (NILP (keep_time)) | 2046 | else if (NILP (keep_time)) |
| 2050 | { | 2047 | { |
| 2051 | EMACS_TIME now; | 2048 | struct timespec now; |
| 2052 | DWORD attributes; | 2049 | DWORD attributes; |
| 2053 | char * filename; | 2050 | char * filename; |
| 2054 | 2051 | ||
| @@ -2057,7 +2054,7 @@ entries (depending on how Emacs was built). */) | |||
| 2057 | /* Ensure file is writable while its modified time is set. */ | 2054 | /* Ensure file is writable while its modified time is set. */ |
| 2058 | attributes = GetFileAttributes (filename); | 2055 | attributes = GetFileAttributes (filename); |
| 2059 | SetFileAttributes (filename, attributes & ~FILE_ATTRIBUTE_READONLY); | 2056 | SetFileAttributes (filename, attributes & ~FILE_ATTRIBUTE_READONLY); |
| 2060 | now = current_emacs_time (); | 2057 | now = current_timespec (); |
| 2061 | if (set_file_times (-1, filename, now, now)) | 2058 | if (set_file_times (-1, filename, now, now)) |
| 2062 | { | 2059 | { |
| 2063 | /* Restore original attributes. */ | 2060 | /* Restore original attributes. */ |
| @@ -2181,8 +2178,8 @@ entries (depending on how Emacs was built). */) | |||
| 2181 | 2178 | ||
| 2182 | if (!NILP (keep_time)) | 2179 | if (!NILP (keep_time)) |
| 2183 | { | 2180 | { |
| 2184 | EMACS_TIME atime = get_stat_atime (&st); | 2181 | struct timespec atime = get_stat_atime (&st); |
| 2185 | EMACS_TIME mtime = get_stat_mtime (&st); | 2182 | struct timespec mtime = get_stat_mtime (&st); |
| 2186 | if (set_file_times (ofd, SSDATA (encoded_newname), atime, mtime)) | 2183 | if (set_file_times (ofd, SSDATA (encoded_newname), atime, mtime)) |
| 2187 | xsignal2 (Qfile_date_error, | 2184 | xsignal2 (Qfile_date_error, |
| 2188 | build_string ("Cannot set file date"), newname); | 2185 | build_string ("Cannot set file date"), newname); |
| @@ -3289,7 +3286,7 @@ Use the current time if TIMESTAMP is nil. TIMESTAMP is in the format of | |||
| 3289 | { | 3286 | { |
| 3290 | Lisp_Object absname, encoded_absname; | 3287 | Lisp_Object absname, encoded_absname; |
| 3291 | Lisp_Object handler; | 3288 | Lisp_Object handler; |
| 3292 | EMACS_TIME t = lisp_time_argument (timestamp); | 3289 | struct timespec t = lisp_time_argument (timestamp); |
| 3293 | 3290 | ||
| 3294 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)); | 3291 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)); |
| 3295 | 3292 | ||
| @@ -3366,7 +3363,7 @@ otherwise, if FILE2 does not exist, the answer is t. */) | |||
| 3366 | if (stat (SSDATA (absname2), &st2) < 0) | 3363 | if (stat (SSDATA (absname2), &st2) < 0) |
| 3367 | return Qt; | 3364 | return Qt; |
| 3368 | 3365 | ||
| 3369 | return (EMACS_TIME_LT (get_stat_mtime (&st2), get_stat_mtime (&st1)) | 3366 | return (timespec_cmp (get_stat_mtime (&st2), get_stat_mtime (&st1)) < 0 |
| 3370 | ? Qt : Qnil); | 3367 | ? Qt : Qnil); |
| 3371 | } | 3368 | } |
| 3372 | 3369 | ||
| @@ -3466,13 +3463,13 @@ file_offset (Lisp_Object val) | |||
| 3466 | } | 3463 | } |
| 3467 | 3464 | ||
| 3468 | /* Return a special time value indicating the error number ERRNUM. */ | 3465 | /* Return a special time value indicating the error number ERRNUM. */ |
| 3469 | static EMACS_TIME | 3466 | static struct timespec |
| 3470 | time_error_value (int errnum) | 3467 | time_error_value (int errnum) |
| 3471 | { | 3468 | { |
| 3472 | int ns = (errnum == ENOENT || errnum == EACCES || errnum == ENOTDIR | 3469 | int ns = (errnum == ENOENT || errnum == EACCES || errnum == ENOTDIR |
| 3473 | ? NONEXISTENT_MODTIME_NSECS | 3470 | ? NONEXISTENT_MODTIME_NSECS |
| 3474 | : UNKNOWN_MODTIME_NSECS); | 3471 | : UNKNOWN_MODTIME_NSECS); |
| 3475 | return make_emacs_time (0, ns); | 3472 | return make_timespec (0, ns); |
| 3476 | } | 3473 | } |
| 3477 | 3474 | ||
| 3478 | DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, | 3475 | DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, |
| @@ -3504,7 +3501,7 @@ by calling `format-decode', which see. */) | |||
| 3504 | (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace) | 3501 | (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace) |
| 3505 | { | 3502 | { |
| 3506 | struct stat st; | 3503 | struct stat st; |
| 3507 | EMACS_TIME mtime; | 3504 | struct timespec mtime; |
| 3508 | int fd; | 3505 | int fd; |
| 3509 | ptrdiff_t inserted = 0; | 3506 | ptrdiff_t inserted = 0; |
| 3510 | ptrdiff_t how_much; | 3507 | ptrdiff_t how_much; |
| @@ -4570,7 +4567,7 @@ by calling `format-decode', which see. */) | |||
| 4570 | } | 4567 | } |
| 4571 | 4568 | ||
| 4572 | if (!NILP (visit) | 4569 | if (!NILP (visit) |
| 4573 | && EMACS_NSECS (current_buffer->modtime) == NONEXISTENT_MODTIME_NSECS) | 4570 | && current_buffer->modtime.tv_nsec == NONEXISTENT_MODTIME_NSECS) |
| 4574 | { | 4571 | { |
| 4575 | /* If visiting nonexistent file, return nil. */ | 4572 | /* If visiting nonexistent file, return nil. */ |
| 4576 | report_file_errno ("Opening input file", orig_filename, save_errno); | 4573 | report_file_errno ("Opening input file", orig_filename, save_errno); |
| @@ -4746,25 +4743,39 @@ This does code conversion according to the value of | |||
| 4746 | 4743 | ||
| 4747 | This calls `write-region-annotate-functions' at the start, and | 4744 | This calls `write-region-annotate-functions' at the start, and |
| 4748 | `write-region-post-annotation-function' at the end. */) | 4745 | `write-region-post-annotation-function' at the end. */) |
| 4749 | (Lisp_Object start, Lisp_Object end, Lisp_Object filename, Lisp_Object append, Lisp_Object visit, Lisp_Object lockname, Lisp_Object mustbenew) | 4746 | (Lisp_Object start, Lisp_Object end, Lisp_Object filename, Lisp_Object append, |
| 4747 | Lisp_Object visit, Lisp_Object lockname, Lisp_Object mustbenew) | ||
| 4748 | { | ||
| 4749 | return write_region (start, end, filename, append, visit, lockname, mustbenew, | ||
| 4750 | -1); | ||
| 4751 | } | ||
| 4752 | |||
| 4753 | /* Like Fwrite_region, except that if DESC is nonnegative, it is a file | ||
| 4754 | descriptor for FILENAME, so do not open or close FILENAME. */ | ||
| 4755 | |||
| 4756 | Lisp_Object | ||
| 4757 | write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, | ||
| 4758 | Lisp_Object append, Lisp_Object visit, Lisp_Object lockname, | ||
| 4759 | Lisp_Object mustbenew, int desc) | ||
| 4750 | { | 4760 | { |
| 4751 | int desc; | ||
| 4752 | int open_flags; | 4761 | int open_flags; |
| 4753 | int mode; | 4762 | int mode; |
| 4754 | off_t offset IF_LINT (= 0); | 4763 | off_t offset IF_LINT (= 0); |
| 4764 | bool open_and_close_file = desc < 0; | ||
| 4755 | bool ok; | 4765 | bool ok; |
| 4756 | int save_errno = 0; | 4766 | int save_errno = 0; |
| 4757 | const char *fn; | 4767 | const char *fn; |
| 4758 | struct stat st; | 4768 | struct stat st; |
| 4759 | EMACS_TIME modtime; | 4769 | struct timespec modtime; |
| 4760 | ptrdiff_t count = SPECPDL_INDEX (); | 4770 | ptrdiff_t count = SPECPDL_INDEX (); |
| 4761 | ptrdiff_t count1; | 4771 | ptrdiff_t count1 IF_LINT (= 0); |
| 4762 | Lisp_Object handler; | 4772 | Lisp_Object handler; |
| 4763 | Lisp_Object visit_file; | 4773 | Lisp_Object visit_file; |
| 4764 | Lisp_Object annotations; | 4774 | Lisp_Object annotations; |
| 4765 | Lisp_Object encoded_filename; | 4775 | Lisp_Object encoded_filename; |
| 4766 | bool visiting = (EQ (visit, Qt) || STRINGP (visit)); | 4776 | bool visiting = (EQ (visit, Qt) || STRINGP (visit)); |
| 4767 | bool quietly = !NILP (visit); | 4777 | bool quietly = !NILP (visit); |
| 4778 | bool file_locked = 0; | ||
| 4768 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | 4779 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; |
| 4769 | struct buffer *given_buffer; | 4780 | struct buffer *given_buffer; |
| 4770 | struct coding_system coding; | 4781 | struct coding_system coding; |
| @@ -4832,7 +4843,6 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4832 | record_unwind_protect (build_annotations_unwind, | 4843 | record_unwind_protect (build_annotations_unwind, |
| 4833 | Vwrite_region_annotation_buffers); | 4844 | Vwrite_region_annotation_buffers); |
| 4834 | Vwrite_region_annotation_buffers = list1 (Fcurrent_buffer ()); | 4845 | Vwrite_region_annotation_buffers = list1 (Fcurrent_buffer ()); |
| 4835 | count1 = SPECPDL_INDEX (); | ||
| 4836 | 4846 | ||
| 4837 | given_buffer = current_buffer; | 4847 | given_buffer = current_buffer; |
| 4838 | 4848 | ||
| @@ -4871,8 +4881,11 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4871 | coding.mode |= CODING_MODE_SELECTIVE_DISPLAY; | 4881 | coding.mode |= CODING_MODE_SELECTIVE_DISPLAY; |
| 4872 | 4882 | ||
| 4873 | #ifdef CLASH_DETECTION | 4883 | #ifdef CLASH_DETECTION |
| 4874 | if (!auto_saving) | 4884 | if (open_and_close_file && !auto_saving) |
| 4875 | lock_file (lockname); | 4885 | { |
| 4886 | lock_file (lockname); | ||
| 4887 | file_locked = 1; | ||
| 4888 | } | ||
| 4876 | #endif /* CLASH_DETECTION */ | 4889 | #endif /* CLASH_DETECTION */ |
| 4877 | 4890 | ||
| 4878 | encoded_filename = ENCODE_FILE (filename); | 4891 | encoded_filename = ENCODE_FILE (filename); |
| @@ -4889,19 +4902,23 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4889 | mode = auto_saving ? auto_save_mode_bits : 0666; | 4902 | mode = auto_saving ? auto_save_mode_bits : 0666; |
| 4890 | #endif | 4903 | #endif |
| 4891 | 4904 | ||
| 4892 | desc = emacs_open (fn, open_flags, mode); | 4905 | if (open_and_close_file) |
| 4893 | |||
| 4894 | if (desc < 0) | ||
| 4895 | { | 4906 | { |
| 4896 | int open_errno = errno; | 4907 | desc = emacs_open (fn, open_flags, mode); |
| 4908 | if (desc < 0) | ||
| 4909 | { | ||
| 4910 | int open_errno = errno; | ||
| 4897 | #ifdef CLASH_DETECTION | 4911 | #ifdef CLASH_DETECTION |
| 4898 | if (!auto_saving) unlock_file (lockname); | 4912 | if (file_locked) |
| 4913 | unlock_file (lockname); | ||
| 4899 | #endif /* CLASH_DETECTION */ | 4914 | #endif /* CLASH_DETECTION */ |
| 4900 | UNGCPRO; | 4915 | UNGCPRO; |
| 4901 | report_file_errno ("Opening output file", filename, open_errno); | 4916 | report_file_errno ("Opening output file", filename, open_errno); |
| 4902 | } | 4917 | } |
| 4903 | 4918 | ||
| 4904 | record_unwind_protect_int (close_file_unwind, desc); | 4919 | count1 = SPECPDL_INDEX (); |
| 4920 | record_unwind_protect_int (close_file_unwind, desc); | ||
| 4921 | } | ||
| 4905 | 4922 | ||
| 4906 | if (NUMBERP (append)) | 4923 | if (NUMBERP (append)) |
| 4907 | { | 4924 | { |
| @@ -4910,7 +4927,8 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4910 | { | 4927 | { |
| 4911 | int lseek_errno = errno; | 4928 | int lseek_errno = errno; |
| 4912 | #ifdef CLASH_DETECTION | 4929 | #ifdef CLASH_DETECTION |
| 4913 | if (!auto_saving) unlock_file (lockname); | 4930 | if (file_locked) |
| 4931 | unlock_file (lockname); | ||
| 4914 | #endif /* CLASH_DETECTION */ | 4932 | #endif /* CLASH_DETECTION */ |
| 4915 | UNGCPRO; | 4933 | UNGCPRO; |
| 4916 | report_file_errno ("Lseek error", filename, lseek_errno); | 4934 | report_file_errno ("Lseek error", filename, lseek_errno); |
| @@ -4945,9 +4963,9 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4945 | 4963 | ||
| 4946 | immediate_quit = 0; | 4964 | immediate_quit = 0; |
| 4947 | 4965 | ||
| 4948 | /* fsync is not crucial for auto-save files, since they might lose | 4966 | /* fsync is not crucial for temporary files. Nor for auto-save |
| 4949 | some work anyway. */ | 4967 | files, since they might lose some work anyway. */ |
| 4950 | if (!auto_saving && !write_region_inhibit_fsync) | 4968 | if (open_and_close_file && !auto_saving && !write_region_inhibit_fsync) |
| 4951 | { | 4969 | { |
| 4952 | /* Transfer data and metadata to disk, retrying if interrupted. | 4970 | /* Transfer data and metadata to disk, retrying if interrupted. |
| 4953 | fsync can report a write failure here, e.g., due to disk full | 4971 | fsync can report a write failure here, e.g., due to disk full |
| @@ -4962,7 +4980,7 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4962 | } | 4980 | } |
| 4963 | } | 4981 | } |
| 4964 | 4982 | ||
| 4965 | modtime = invalid_emacs_time (); | 4983 | modtime = invalid_timespec (); |
| 4966 | if (visiting) | 4984 | if (visiting) |
| 4967 | { | 4985 | { |
| 4968 | if (fstat (desc, &st) == 0) | 4986 | if (fstat (desc, &st) == 0) |
| @@ -4971,12 +4989,15 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4971 | ok = 0, save_errno = errno; | 4989 | ok = 0, save_errno = errno; |
| 4972 | } | 4990 | } |
| 4973 | 4991 | ||
| 4974 | /* NFS can report a write failure now. */ | 4992 | if (open_and_close_file) |
| 4975 | if (emacs_close (desc) < 0) | 4993 | { |
| 4976 | ok = 0, save_errno = errno; | 4994 | /* NFS can report a write failure now. */ |
| 4995 | if (emacs_close (desc) < 0) | ||
| 4996 | ok = 0, save_errno = errno; | ||
| 4977 | 4997 | ||
| 4978 | /* Discard the unwind protect for close_file_unwind. */ | 4998 | /* Discard the unwind protect for close_file_unwind. */ |
| 4979 | specpdl_ptr = specpdl + count1; | 4999 | specpdl_ptr = specpdl + count1; |
| 5000 | } | ||
| 4980 | 5001 | ||
| 4981 | /* Some file systems have a bug where st_mtime is not updated | 5002 | /* Some file systems have a bug where st_mtime is not updated |
| 4982 | properly after a write. For example, CIFS might not see the | 5003 | properly after a write. For example, CIFS might not see the |
| @@ -4993,7 +5014,7 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4993 | unlikely and a similar race between the last write and the fstat | 5014 | unlikely and a similar race between the last write and the fstat |
| 4994 | above cannot possibly be closed anyway. */ | 5015 | above cannot possibly be closed anyway. */ |
| 4995 | 5016 | ||
| 4996 | if (EMACS_TIME_VALID_P (modtime) | 5017 | if (timespec_valid_p (modtime) |
| 4997 | && ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system)) | 5018 | && ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system)) |
| 4998 | { | 5019 | { |
| 4999 | int desc1 = emacs_open (fn, O_WRONLY | O_BINARY, 0); | 5020 | int desc1 = emacs_open (fn, O_WRONLY | O_BINARY, 0); |
| @@ -5015,11 +5036,11 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 5015 | bool use_heuristic | 5036 | bool use_heuristic |
| 5016 | = ((open_flags & (O_EXCL | O_TRUNC)) != 0 | 5037 | = ((open_flags & (O_EXCL | O_TRUNC)) != 0 |
| 5017 | && st.st_size != 0 | 5038 | && st.st_size != 0 |
| 5018 | && EMACS_NSECS (modtime) % 100 != 0); | 5039 | && modtime.tv_nsec % 100 != 0); |
| 5019 | 5040 | ||
| 5020 | EMACS_TIME modtime1 = get_stat_mtime (&st1); | 5041 | struct timespec modtime1 = get_stat_mtime (&st1); |
| 5021 | if (use_heuristic | 5042 | if (use_heuristic |
| 5022 | && EMACS_TIME_EQ (modtime, modtime1) | 5043 | && timespec_cmp (modtime, modtime1) == 0 |
| 5023 | && st.st_size == st1.st_size) | 5044 | && st.st_size == st1.st_size) |
| 5024 | { | 5045 | { |
| 5025 | timestamp_file_system = st.st_dev; | 5046 | timestamp_file_system = st.st_dev; |
| @@ -5052,14 +5073,14 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 5052 | unbind_to (count, Qnil); | 5073 | unbind_to (count, Qnil); |
| 5053 | 5074 | ||
| 5054 | #ifdef CLASH_DETECTION | 5075 | #ifdef CLASH_DETECTION |
| 5055 | if (!auto_saving) | 5076 | if (file_locked) |
| 5056 | unlock_file (lockname); | 5077 | unlock_file (lockname); |
| 5057 | #endif /* CLASH_DETECTION */ | 5078 | #endif /* CLASH_DETECTION */ |
| 5058 | 5079 | ||
| 5059 | /* Do this before reporting IO error | 5080 | /* Do this before reporting IO error |
| 5060 | to avoid a "file has changed on disk" warning on | 5081 | to avoid a "file has changed on disk" warning on |
| 5061 | next attempt to save. */ | 5082 | next attempt to save. */ |
| 5062 | if (EMACS_TIME_VALID_P (modtime)) | 5083 | if (timespec_valid_p (modtime)) |
| 5063 | { | 5084 | { |
| 5064 | current_buffer->modtime = modtime; | 5085 | current_buffer->modtime = modtime; |
| 5065 | current_buffer->modtime_size = st.st_size; | 5086 | current_buffer->modtime_size = st.st_size; |
| @@ -5334,7 +5355,7 @@ See Info node `(elisp)Modification Time' for more details. */) | |||
| 5334 | struct stat st; | 5355 | struct stat st; |
| 5335 | Lisp_Object handler; | 5356 | Lisp_Object handler; |
| 5336 | Lisp_Object filename; | 5357 | Lisp_Object filename; |
| 5337 | EMACS_TIME mtime; | 5358 | struct timespec mtime; |
| 5338 | 5359 | ||
| 5339 | if (NILP (buf)) | 5360 | if (NILP (buf)) |
| 5340 | b = current_buffer; | 5361 | b = current_buffer; |
| @@ -5345,7 +5366,7 @@ See Info node `(elisp)Modification Time' for more details. */) | |||
| 5345 | } | 5366 | } |
| 5346 | 5367 | ||
| 5347 | if (!STRINGP (BVAR (b, filename))) return Qt; | 5368 | if (!STRINGP (BVAR (b, filename))) return Qt; |
| 5348 | if (EMACS_NSECS (b->modtime) == UNKNOWN_MODTIME_NSECS) return Qt; | 5369 | if (b->modtime.tv_nsec == UNKNOWN_MODTIME_NSECS) return Qt; |
| 5349 | 5370 | ||
| 5350 | /* If the file name has special constructs in it, | 5371 | /* If the file name has special constructs in it, |
| 5351 | call the corresponding file handler. */ | 5372 | call the corresponding file handler. */ |
| @@ -5359,7 +5380,7 @@ See Info node `(elisp)Modification Time' for more details. */) | |||
| 5359 | mtime = (stat (SSDATA (filename), &st) == 0 | 5380 | mtime = (stat (SSDATA (filename), &st) == 0 |
| 5360 | ? get_stat_mtime (&st) | 5381 | ? get_stat_mtime (&st) |
| 5361 | : time_error_value (errno)); | 5382 | : time_error_value (errno)); |
| 5362 | if (EMACS_TIME_EQ (mtime, b->modtime) | 5383 | if (timespec_cmp (mtime, b->modtime) == 0 |
| 5363 | && (b->modtime_size < 0 | 5384 | && (b->modtime_size < 0 |
| 5364 | || st.st_size == b->modtime_size)) | 5385 | || st.st_size == b->modtime_size)) |
| 5365 | return Qt; | 5386 | return Qt; |
| @@ -5376,7 +5397,7 @@ doesn't exist, return -1. | |||
| 5376 | See Info node `(elisp)Modification Time' for more details. */) | 5397 | See Info node `(elisp)Modification Time' for more details. */) |
| 5377 | (void) | 5398 | (void) |
| 5378 | { | 5399 | { |
| 5379 | int ns = EMACS_NSECS (current_buffer->modtime); | 5400 | int ns = current_buffer->modtime.tv_nsec; |
| 5380 | if (ns < 0) | 5401 | if (ns < 0) |
| 5381 | return make_number (UNKNOWN_MODTIME_NSECS - ns); | 5402 | return make_number (UNKNOWN_MODTIME_NSECS - ns); |
| 5382 | return make_lisp_time (current_buffer->modtime); | 5403 | return make_lisp_time (current_buffer->modtime); |
| @@ -5395,11 +5416,11 @@ An argument specifies the modification time value to use | |||
| 5395 | { | 5416 | { |
| 5396 | if (!NILP (time_flag)) | 5417 | if (!NILP (time_flag)) |
| 5397 | { | 5418 | { |
| 5398 | EMACS_TIME mtime; | 5419 | struct timespec mtime; |
| 5399 | if (INTEGERP (time_flag)) | 5420 | if (INTEGERP (time_flag)) |
| 5400 | { | 5421 | { |
| 5401 | CHECK_RANGED_INTEGER (time_flag, -1, 0); | 5422 | CHECK_RANGED_INTEGER (time_flag, -1, 0); |
| 5402 | mtime = make_emacs_time (0, UNKNOWN_MODTIME_NSECS - XINT (time_flag)); | 5423 | mtime = make_timespec (0, UNKNOWN_MODTIME_NSECS - XINT (time_flag)); |
| 5403 | } | 5424 | } |
| 5404 | else | 5425 | else |
| 5405 | mtime = lisp_time_argument (time_flag); | 5426 | mtime = lisp_time_argument (time_flag); |
| @@ -5618,9 +5639,8 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) | |||
| 5618 | couldn't handle some ange-ftp'd file. */ | 5639 | couldn't handle some ange-ftp'd file. */ |
| 5619 | 5640 | ||
| 5620 | for (do_handled_files = 0; do_handled_files < 2; do_handled_files++) | 5641 | for (do_handled_files = 0; do_handled_files < 2; do_handled_files++) |
| 5621 | for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail)) | 5642 | FOR_EACH_LIVE_BUFFER (tail, buf) |
| 5622 | { | 5643 | { |
| 5623 | buf = XCDR (XCAR (tail)); | ||
| 5624 | b = XBUFFER (buf); | 5644 | b = XBUFFER (buf); |
| 5625 | 5645 | ||
| 5626 | /* Record all the buffers that have auto save mode | 5646 | /* Record all the buffers that have auto save mode |
| @@ -5663,12 +5683,12 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) | |||
| 5663 | || NILP (Ffind_file_name_handler (BVAR (b, auto_save_file_name), | 5683 | || NILP (Ffind_file_name_handler (BVAR (b, auto_save_file_name), |
| 5664 | Qwrite_region)))) | 5684 | Qwrite_region)))) |
| 5665 | { | 5685 | { |
| 5666 | EMACS_TIME before_time = current_emacs_time (); | 5686 | struct timespec before_time = current_timespec (); |
| 5667 | EMACS_TIME after_time; | 5687 | struct timespec after_time; |
| 5668 | 5688 | ||
| 5669 | /* If we had a failure, don't try again for 20 minutes. */ | 5689 | /* If we had a failure, don't try again for 20 minutes. */ |
| 5670 | if (b->auto_save_failure_time > 0 | 5690 | if (b->auto_save_failure_time > 0 |
| 5671 | && EMACS_SECS (before_time) - b->auto_save_failure_time < 1200) | 5691 | && before_time.tv_sec - b->auto_save_failure_time < 1200) |
| 5672 | continue; | 5692 | continue; |
| 5673 | 5693 | ||
| 5674 | set_buffer_internal (b); | 5694 | set_buffer_internal (b); |
| @@ -5701,12 +5721,12 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) | |||
| 5701 | XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG); | 5721 | XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG); |
| 5702 | set_buffer_internal (old); | 5722 | set_buffer_internal (old); |
| 5703 | 5723 | ||
| 5704 | after_time = current_emacs_time (); | 5724 | after_time = current_timespec (); |
| 5705 | 5725 | ||
| 5706 | /* If auto-save took more than 60 seconds, | 5726 | /* If auto-save took more than 60 seconds, |
| 5707 | assume it was an NFS failure that got a timeout. */ | 5727 | assume it was an NFS failure that got a timeout. */ |
| 5708 | if (EMACS_SECS (after_time) - EMACS_SECS (before_time) > 60) | 5728 | if (after_time.tv_sec - before_time.tv_sec > 60) |
| 5709 | b->auto_save_failure_time = EMACS_SECS (after_time); | 5729 | b->auto_save_failure_time = after_time.tv_sec; |
| 5710 | } | 5730 | } |
| 5711 | } | 5731 | } |
| 5712 | 5732 | ||