Mercurial > hg > xemacs-beta
diff src/fileio.c @ 274:ca9a9ec9c1c1 r21-0b35
Import from CVS: tag r21-0b35
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:29:42 +0200 |
parents | c5d627a313b1 |
children | 6330739388db |
line wrap: on
line diff
--- a/src/fileio.c Mon Aug 13 10:28:54 2007 +0200 +++ b/src/fileio.c Mon Aug 13 10:29:42 2007 +0200 @@ -641,32 +641,126 @@ directory_file_name ((char *) XSTRING_DATA (directory), buf); return build_string (buf); } + +/* Fmake_temp_name used to be a simple wrapper around mktemp(), but it + proved too broken for our purposes (it supported only 26 or 62 + unique names under some implementations). For instance, the stupid + limit broke Gnus Incoming* files generation. + + NB, this implementation is better than what one usually finds in + libc. --hniksic */ + +#define MTN_RANDOM(x) ((int) (random () % x)) +#define MTN_INC(var, limit) (var = ((var == (limit) - 1) ? 0 : (var + 1))) +#define MTN_LOOP(var, limit, keep) \ +for (keep = var = MTN_RANDOM (limit), MTN_INC (var, limit); \ + var != keep; \ + MTN_INC (var, limit)) DEFUN ("make-temp-name", Fmake_temp_name, 1, 1, 0, /* -Generate temporary file name (string) starting with PREFIX (a string). -The Emacs process number forms part of the result, -so there is no danger of generating a name being used by another process. +Generate temporary file name starting with PREFIX. +The Emacs process number forms part of the result, so there is no +danger of generating a name being used by another process. + +In its current implementation, this function guarantees 262144 unique +names per process per PREFIX (this is 54872 on case-insensitive +filesystems. However, if you want it to operate safely, PREFIX should +have been passed through `expand-file-name'. */ (prefix)) { - CONST char suffix[] = "XXXXXX"; - Bufbyte *data; + static char tbl[64] = { + 'A','B','C','D','E','F','G','H', + 'I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X', + 'Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3', + '4','5','6','7','8','9','-','_' + }; + Lisp_Object val; Bytecount len; - Lisp_Object val; + int pid; + int i, j, k, keep1, keep2, keep3; + Bufbyte *p, *data; CHECK_STRING (prefix); + + /* I was tempted to apply Fexpand_file_name on PREFIX here, but it's + a bad idea because: + + 1) It might change the prefix, so the resulting string might not + begin with PREFIX. This violates the principle of least + surprise. + + 2) It breaks under many unforeseeable circumstances, such as with + the code that uses (make-temp-name "") instead of + (make-temp-name "./"). + + 3) It might yield unexpected results in the presence of EFS and + file name handlers. */ + len = XSTRING_LENGTH (prefix); - val = make_uninit_string (len + countof (suffix) - 1); + val = make_uninit_string (len + 6); data = XSTRING_DATA (val); memcpy (data, XSTRING_DATA (prefix), len); - memcpy (data + len, suffix, countof (suffix)); - /* !!#### does mktemp() Mule-encapsulate? */ - mktemp ((char *) data); - -#ifdef WINDOWSNT - CORRECT_DIR_SEPS (XSTRING_DATA (val)); -#endif /* WINDOWSNT */ - return val; + p = data + len; + + /* `val' is created by adding 6 characters to PREFIX. The first + three are the PID of this process, in base 64, and the second + three are incremented if the file already exists. This ensures + 262144 unique file names per PID per PREFIX. */ + + pid = (int)getpid (); + *p++ = tbl[pid & 63], pid >>= 6; + *p++ = tbl[pid & 63], pid >>= 6; + *p++ = tbl[pid & 63], pid >>= 6; + + /* Here we employ some trickery to minimize useless stat'ing when + this function is invoked many times successively with the same + PREFIX. Instead of looping from 0 to 63, each of the variables + is assigned a random number less than 64, and is incremented up + to 63 and back to zero, until the initial value is reached again. + + In other words, MTN_LOOP (i, 64, keep1) is equivalent to + for (i = 0; i < 64; i++) with the difference that the beginning + value needn't be 0 -- all that matters is that i is guaranteed to + loop through all the values in the [0, 64) range. */ + MTN_LOOP (i, 64, keep1) + { + p[0] = tbl[i]; + MTN_LOOP (j, 64, keep2) + { + p[1] = tbl[j]; + MTN_LOOP (k, 64, keep3) + { + struct stat ignored; + p[2] = tbl[k]; + if (stat (data, &ignored) < 0) + { + /* We want to return only if errno is ENOENT. */ + if (errno == ENOENT) + return val; + else + /* The error here is dubious, but there is little + else we can do. The alternatives are to return + nil, which is as bad as (and in many cases + worse than) throwing the error, or to ignore + the error, which will likely result in looping + through 262144 stat's, which is not only SLOW, + but also useless since it will fallback to the + errow below, anyway. */ + report_file_error + ("Cannot create temporary name for prefix", + list1 (prefix)); + /* not reached */ + } + } + } + } + signal_simple_error ("Cannot create temporary name for prefix", prefix); + RETURN_NOT_REACHED (Qnil); } DEFUN ("expand-file-name", Fexpand_file_name, 1, 2, 0, /* @@ -2553,8 +2647,7 @@ /* #define READ_BUF_SIZE (2 << 16) */ #define READ_BUF_SIZE (1 << 15) -DEFUN ("insert-file-contents-internal", - Finsert_file_contents_internal, 1, 7, 0, /* +DEFUN ("insert-file-contents-internal", Finsert_file_contents_internal, 1, 7, 0, /* Insert contents of file FILENAME after point; no coding-system frobbing. This function is identical to `insert-file-contents' except for the handling of the CODESYS and USED-CODESYS arguments under @@ -2570,7 +2663,7 @@ Currently BEG and END refer to byte positions (as opposed to character positions), even in Mule. (Fixing this is very difficult.) */ - (filename, visit, beg, end, replace, codesys, used_codesys)) + (filename, visit, beg, end, replace, codesys, used_codesys)) { /* This function can call lisp */ /* #### dmoore - this function hasn't been checked for gc recently */ @@ -2836,8 +2929,9 @@ error ("Maximum buffer size exceeded"); } else - /* For a special file, all we can do is guess. */ - total = READ_BUF_SIZE; + /* For a special file, all we can do is guess. The value of -1 + will make the stream functions read as much as possible. */ + total = -1; if (XINT (beg) != 0 #ifdef FSFMACS_SPEEDY_INSERT @@ -2865,7 +2959,7 @@ (XLSTREAM (stream), Fget_coding_system (codesys)); Lstream_set_character_mode (XLSTREAM (stream)); Lstream_set_buffering (XLSTREAM (stream), LSTREAM_BLOCKN_BUFFERED, 65536); -#endif /* MULE */ +#endif /* FILE_CODING */ record_unwind_protect (close_stream_unwind, stream); @@ -2901,7 +2995,7 @@ Fset (used_codesys, XCODING_SYSTEM_NAME (decoding_stream_coding_system (XLSTREAM (stream)))); } -#endif /* MULE */ +#endif /* FILE_CODING */ NUNGCPRO; } @@ -3052,7 +3146,7 @@ #ifdef FILE_CODING codesys = Fget_coding_system (codesys); -#endif /* MULE */ +#endif /* FILE_CODING */ if (current_buffer->base_buffer && ! NILP (visit)) error ("Cannot do file visiting in an indirect buffer"); @@ -3193,7 +3287,7 @@ make_encoding_output_stream (XLSTREAM (outstream), codesys); Lstream_set_buffering (XLSTREAM (outstream), LSTREAM_BLOCKN_BUFFERED, 65536); -#endif /* MULE */ +#endif /* FILE_CODING */ if (STRINGP (start)) { instream = make_lisp_string_input_stream (start, 0, -1);