Mercurial > vim
comparison src/fileio.c @ 18199:e2be5a6485f5 v8.1.2094
patch 8.1.2094: the fileio.c file is too big
Commit: https://github.com/vim/vim/commit/473952e85286eb9c6098801f1819981ba61ad153
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Sep 28 16:30:04 2019 +0200
patch 8.1.2094: the fileio.c file is too big
Problem: The fileio.c file is too big.
Solution: Move buf_write() to bufwrite.c. (Yegappan Lakshmanan,
closes #4990)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 28 Sep 2019 16:45:04 +0200 |
parents | 59bc3cd42cf5 |
children | 788d76db02ac |
comparison
equal
deleted
inserted
replaced
18198:3ebea66ebaff | 18199:e2be5a6485f5 |
---|---|
15 | 15 |
16 #if defined(__TANDEM) || defined(__MINT__) | 16 #if defined(__TANDEM) || defined(__MINT__) |
17 # include <limits.h> /* for SSIZE_MAX */ | 17 # include <limits.h> /* for SSIZE_MAX */ |
18 #endif | 18 #endif |
19 | 19 |
20 #if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) | |
21 # include <utime.h> /* for struct utimbuf */ | |
22 #endif | |
23 | |
24 #define BUFSIZE 8192 /* size of normal write buffer */ | |
25 #define SMBUFSIZE 256 /* size of emergency write buffer */ | |
26 | |
27 /* Is there any system that doesn't have access()? */ | 20 /* Is there any system that doesn't have access()? */ |
28 #define USE_MCH_ACCESS | 21 #define USE_MCH_ACCESS |
29 | 22 |
30 static char_u *next_fenc(char_u **pp, int *alloced); | 23 static char_u *next_fenc(char_u **pp, int *alloced); |
31 #ifdef FEAT_EVAL | 24 #ifdef FEAT_EVAL |
32 static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp); | 25 static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp); |
33 #endif | 26 #endif |
34 #ifdef FEAT_CRYPT | 27 #ifdef FEAT_CRYPT |
35 static char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, long *sizep, off_T *filesizep, int newfile, char_u *fname, int *did_ask); | 28 static char_u *check_for_cryptkey(char_u *cryptkey, char_u *ptr, long *sizep, off_T *filesizep, int newfile, char_u *fname, int *did_ask); |
36 #endif | 29 #endif |
37 static int set_rw_fname(char_u *fname, char_u *sfname); | |
38 static int msg_add_fileformat(int eol_type); | |
39 static void msg_add_eol(void); | |
40 static int check_mtime(buf_T *buf, stat_T *s); | |
41 static int time_differs(long t1, long t2); | |
42 | |
43 #define HAS_BW_FLAGS | |
44 #define FIO_LATIN1 0x01 /* convert Latin1 */ | |
45 #define FIO_UTF8 0x02 /* convert UTF-8 */ | |
46 #define FIO_UCS2 0x04 /* convert UCS-2 */ | |
47 #define FIO_UCS4 0x08 /* convert UCS-4 */ | |
48 #define FIO_UTF16 0x10 /* convert UTF-16 */ | |
49 #ifdef MSWIN | |
50 # define FIO_CODEPAGE 0x20 /* convert MS-Windows codepage */ | |
51 # define FIO_PUT_CP(x) (((x) & 0xffff) << 16) /* put codepage in top word */ | |
52 # define FIO_GET_CP(x) (((x)>>16) & 0xffff) /* get codepage from top word */ | |
53 #endif | |
54 #ifdef MACOS_CONVERT | |
55 # define FIO_MACROMAN 0x20 /* convert MacRoman */ | |
56 #endif | |
57 #define FIO_ENDIAN_L 0x80 /* little endian */ | |
58 #define FIO_ENCRYPTED 0x1000 /* encrypt written bytes */ | |
59 #define FIO_NOCONVERT 0x2000 /* skip encoding conversion */ | |
60 #define FIO_UCSBOM 0x4000 /* check for BOM at start of file */ | |
61 #define FIO_ALL -1 /* allow all formats */ | |
62 | |
63 /* When converting, a read() or write() may leave some bytes to be converted | |
64 * for the next call. The value is guessed... */ | |
65 #define CONV_RESTLEN 30 | |
66 | |
67 /* We have to guess how much a sequence of bytes may expand when converting | |
68 * with iconv() to be able to allocate a buffer. */ | |
69 #define ICONV_MULT 8 | |
70 | |
71 /* | |
72 * Structure to pass arguments from buf_write() to buf_write_bytes(). | |
73 */ | |
74 struct bw_info | |
75 { | |
76 int bw_fd; /* file descriptor */ | |
77 char_u *bw_buf; /* buffer with data to be written */ | |
78 int bw_len; /* length of data */ | |
79 #ifdef HAS_BW_FLAGS | |
80 int bw_flags; /* FIO_ flags */ | |
81 #endif | |
82 #ifdef FEAT_CRYPT | |
83 buf_T *bw_buffer; /* buffer being written */ | |
84 #endif | |
85 char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */ | |
86 int bw_restlen; /* nr of bytes in bw_rest[] */ | |
87 int bw_first; /* first write call */ | |
88 char_u *bw_conv_buf; /* buffer for writing converted chars */ | |
89 size_t bw_conv_buflen; /* size of bw_conv_buf */ | |
90 int bw_conv_error; /* set for conversion error */ | |
91 linenr_T bw_conv_error_lnum; /* first line with error or zero */ | |
92 linenr_T bw_start_lnum; /* line number at start of buffer */ | |
93 #ifdef USE_ICONV | |
94 iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */ | |
95 #endif | |
96 }; | |
97 | |
98 static int buf_write_bytes(struct bw_info *ip); | |
99 | |
100 static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp); | 30 static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp); |
101 static int ucs2bytes(unsigned c, char_u **pp, int flags); | |
102 static int need_conversion(char_u *fenc); | |
103 static int get_fio_flags(char_u *ptr); | |
104 static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags); | 31 static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags); |
105 static int make_bom(char_u *buf, char_u *name); | |
106 #ifdef MSWIN | |
107 static int get_win_fio_flags(char_u *ptr); | |
108 #endif | |
109 #ifdef MACOS_CONVERT | |
110 static int get_mac_fio_flags(char_u *ptr); | |
111 #endif | |
112 static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); | 32 static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); |
113 | 33 |
114 static void | 34 void |
115 filemess( | 35 filemess( |
116 buf_T *buf, | 36 buf_T *buf, |
117 char_u *name, | 37 char_u *name, |
118 char_u *s, | 38 char_u *s, |
119 int attr) | 39 int attr) |
120 { | 40 { |
121 int msg_scroll_save; | 41 int msg_scroll_save; |
42 int prev_msg_col = msg_col; | |
122 | 43 |
123 if (msg_silent != 0) | 44 if (msg_silent != 0) |
124 return; | 45 return; |
125 msg_add_fname(buf, name); /* put file name in IObuff with quotes */ | 46 msg_add_fname(buf, name); /* put file name in IObuff with quotes */ |
126 /* If it's extremely long, truncate it. */ | 47 /* If it's extremely long, truncate it. */ |
136 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) | 57 if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) |
137 msg_scroll = FALSE; | 58 msg_scroll = FALSE; |
138 if (!msg_scroll) /* wait a bit when overwriting an error msg */ | 59 if (!msg_scroll) /* wait a bit when overwriting an error msg */ |
139 check_for_delay(FALSE); | 60 check_for_delay(FALSE); |
140 msg_start(); | 61 msg_start(); |
62 if (prev_msg_col != 0 && msg_col == 0) | |
63 msg_putchar('\r'); // overwrite any previous message. | |
141 msg_scroll = msg_scroll_save; | 64 msg_scroll = msg_scroll_save; |
142 msg_scrolled_ign = TRUE; | 65 msg_scrolled_ign = TRUE; |
143 /* may truncate the message to avoid a hit-return prompt */ | 66 /* may truncate the message to avoid a hit-return prompt */ |
144 msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr); | 67 msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr); |
145 msg_clr_eos(); | 68 msg_clr_eos(); |
2510 * message box (which might be shown when exiting!) */ | 2433 * message box (which might be shown when exiting!) */ |
2511 if (read_stdin || read_buffer) | 2434 if (read_stdin || read_buffer) |
2512 p = msg_may_trunc(FALSE, IObuff); | 2435 p = msg_may_trunc(FALSE, IObuff); |
2513 else | 2436 else |
2514 #endif | 2437 #endif |
2438 { | |
2439 if (msg_col > 0) | |
2440 msg_putchar('\r'); // overwrite previous message | |
2515 p = (char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0); | 2441 p = (char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0); |
2442 } | |
2516 if (read_stdin || read_buffer || restart_edit != 0 | 2443 if (read_stdin || read_buffer || restart_edit != 0 |
2517 || (msg_scrolled != 0 && !need_wait_return)) | 2444 || (msg_scrolled != 0 && !need_wait_return)) |
2518 /* Need to repeat the message after redrawing when: | 2445 /* Need to repeat the message after redrawing when: |
2519 * - When reading from stdin (the screen will be cleared next). | 2446 * - When reading from stdin (the screen will be cleared next). |
2520 * - When restart_edit is set (otherwise there will be a delay | 2447 * - When restart_edit is set (otherwise there will be a delay |
2937 | 2864 |
2938 return cryptkey; | 2865 return cryptkey; |
2939 } | 2866 } |
2940 #endif /* FEAT_CRYPT */ | 2867 #endif /* FEAT_CRYPT */ |
2941 | 2868 |
2942 #ifdef UNIX | |
2943 static void | |
2944 set_file_time( | |
2945 char_u *fname, | |
2946 time_t atime, /* access time */ | |
2947 time_t mtime) /* modification time */ | |
2948 { | |
2949 # if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) | |
2950 struct utimbuf buf; | |
2951 | |
2952 buf.actime = atime; | |
2953 buf.modtime = mtime; | |
2954 (void)utime((char *)fname, &buf); | |
2955 # else | |
2956 # if defined(HAVE_UTIMES) | |
2957 struct timeval tvp[2]; | |
2958 | |
2959 tvp[0].tv_sec = atime; | |
2960 tvp[0].tv_usec = 0; | |
2961 tvp[1].tv_sec = mtime; | |
2962 tvp[1].tv_usec = 0; | |
2963 # ifdef NeXT | |
2964 (void)utimes((char *)fname, tvp); | |
2965 # else | |
2966 (void)utimes((char *)fname, (const struct timeval *)&tvp); | |
2967 # endif | |
2968 # endif | |
2969 # endif | |
2970 } | |
2971 #endif /* UNIX */ | |
2972 | |
2973 #if defined(VMS) && !defined(MIN) | 2869 #if defined(VMS) && !defined(MIN) |
2974 /* Older DECC compiler for VAX doesn't define MIN() */ | 2870 /* Older DECC compiler for VAX doesn't define MIN() */ |
2975 # define MIN(a, b) ((a) < (b) ? (a) : (b)) | 2871 # define MIN(a, b) ((a) < (b) ? (a) : (b)) |
2976 #endif | 2872 #endif |
2977 | 2873 |
2998 ? TRUE : (close(fd), FALSE) | 2894 ? TRUE : (close(fd), FALSE) |
2999 #endif | 2895 #endif |
3000 ); | 2896 ); |
3001 } | 2897 } |
3002 | 2898 |
3003 | |
3004 /* | |
3005 * buf_write() - write to file "fname" lines "start" through "end" | |
3006 * | |
3007 * We do our own buffering here because fwrite() is so slow. | |
3008 * | |
3009 * If "forceit" is true, we don't care for errors when attempting backups. | |
3010 * In case of an error everything possible is done to restore the original | |
3011 * file. But when "forceit" is TRUE, we risk losing it. | |
3012 * | |
3013 * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and | |
3014 * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed. | |
3015 * | |
3016 * This function must NOT use NameBuff (because it's called by autowrite()). | |
3017 * | |
3018 * return FAIL for failure, OK otherwise | |
3019 */ | |
3020 int | |
3021 buf_write( | |
3022 buf_T *buf, | |
3023 char_u *fname, | |
3024 char_u *sfname, | |
3025 linenr_T start, | |
3026 linenr_T end, | |
3027 exarg_T *eap, /* for forced 'ff' and 'fenc', can be | |
3028 NULL! */ | |
3029 int append, /* append to the file */ | |
3030 int forceit, | |
3031 int reset_changed, | |
3032 int filtering) | |
3033 { | |
3034 int fd; | |
3035 char_u *backup = NULL; | |
3036 int backup_copy = FALSE; /* copy the original file? */ | |
3037 int dobackup; | |
3038 char_u *ffname; | |
3039 char_u *wfname = NULL; /* name of file to write to */ | |
3040 char_u *s; | |
3041 char_u *ptr; | |
3042 char_u c; | |
3043 int len; | |
3044 linenr_T lnum; | |
3045 long nchars; | |
3046 char_u *errmsg = NULL; | |
3047 int errmsg_allocated = FALSE; | |
3048 char_u *errnum = NULL; | |
3049 char_u *buffer; | |
3050 char_u smallbuf[SMBUFSIZE]; | |
3051 char_u *backup_ext; | |
3052 int bufsize; | |
3053 long perm; /* file permissions */ | |
3054 int retval = OK; | |
3055 int newfile = FALSE; /* TRUE if file doesn't exist yet */ | |
3056 int msg_save = msg_scroll; | |
3057 int overwriting; /* TRUE if writing over original */ | |
3058 int no_eol = FALSE; /* no end-of-line written */ | |
3059 int device = FALSE; /* writing to a device */ | |
3060 stat_T st_old; | |
3061 int prev_got_int = got_int; | |
3062 int checking_conversion; | |
3063 int file_readonly = FALSE; /* overwritten file is read-only */ | |
3064 static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')"; | |
3065 #if defined(UNIX) /*XXX fix me sometime? */ | |
3066 int made_writable = FALSE; /* 'w' bit has been set */ | |
3067 #endif | |
3068 /* writing everything */ | |
3069 int whole = (start == 1 && end == buf->b_ml.ml_line_count); | |
3070 linenr_T old_line_count = buf->b_ml.ml_line_count; | |
3071 int attr; | |
3072 int fileformat; | |
3073 int write_bin; | |
3074 struct bw_info write_info; /* info for buf_write_bytes() */ | |
3075 int converted = FALSE; | |
3076 int notconverted = FALSE; | |
3077 char_u *fenc; /* effective 'fileencoding' */ | |
3078 char_u *fenc_tofree = NULL; /* allocated "fenc" */ | |
3079 #ifdef HAS_BW_FLAGS | |
3080 int wb_flags = 0; | |
3081 #endif | |
3082 #ifdef HAVE_ACL | |
3083 vim_acl_T acl = NULL; /* ACL copied from original file to | |
3084 backup or new file */ | |
3085 #endif | |
3086 #ifdef FEAT_PERSISTENT_UNDO | |
3087 int write_undo_file = FALSE; | |
3088 context_sha256_T sha_ctx; | |
3089 #endif | |
3090 unsigned int bkc = get_bkc_value(buf); | |
3091 | |
3092 if (fname == NULL || *fname == NUL) /* safety check */ | |
3093 return FAIL; | |
3094 if (buf->b_ml.ml_mfp == NULL) | |
3095 { | |
3096 /* This can happen during startup when there is a stray "w" in the | |
3097 * vimrc file. */ | |
3098 emsg(_(e_emptybuf)); | |
3099 return FAIL; | |
3100 } | |
3101 | |
3102 /* | |
3103 * Disallow writing from .exrc and .vimrc in current directory for | |
3104 * security reasons. | |
3105 */ | |
3106 if (check_secure()) | |
3107 return FAIL; | |
3108 | |
3109 /* Avoid a crash for a long name. */ | |
3110 if (STRLEN(fname) >= MAXPATHL) | |
3111 { | |
3112 emsg(_(e_longname)); | |
3113 return FAIL; | |
3114 } | |
3115 | |
3116 /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */ | |
3117 write_info.bw_conv_buf = NULL; | |
3118 write_info.bw_conv_error = FALSE; | |
3119 write_info.bw_conv_error_lnum = 0; | |
3120 write_info.bw_restlen = 0; | |
3121 #ifdef USE_ICONV | |
3122 write_info.bw_iconv_fd = (iconv_t)-1; | |
3123 #endif | |
3124 #ifdef FEAT_CRYPT | |
3125 write_info.bw_buffer = buf; | |
3126 #endif | |
3127 | |
3128 /* After writing a file changedtick changes but we don't want to display | |
3129 * the line. */ | |
3130 ex_no_reprint = TRUE; | |
3131 | |
3132 /* | |
3133 * If there is no file name yet, use the one for the written file. | |
3134 * BF_NOTEDITED is set to reflect this (in case the write fails). | |
3135 * Don't do this when the write is for a filter command. | |
3136 * Don't do this when appending. | |
3137 * Only do this when 'cpoptions' contains the 'F' flag. | |
3138 */ | |
3139 if (buf->b_ffname == NULL | |
3140 && reset_changed | |
3141 && whole | |
3142 && buf == curbuf | |
3143 #ifdef FEAT_QUICKFIX | |
3144 && !bt_nofilename(buf) | |
3145 #endif | |
3146 && !filtering | |
3147 && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) | |
3148 && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) | |
3149 { | |
3150 if (set_rw_fname(fname, sfname) == FAIL) | |
3151 return FAIL; | |
3152 buf = curbuf; /* just in case autocmds made "buf" invalid */ | |
3153 } | |
3154 | |
3155 if (sfname == NULL) | |
3156 sfname = fname; | |
3157 /* | |
3158 * For Unix: Use the short file name whenever possible. | |
3159 * Avoids problems with networks and when directory names are changed. | |
3160 * Don't do this for MS-DOS, a "cd" in a sub-shell may have moved us to | |
3161 * another directory, which we don't detect | |
3162 */ | |
3163 ffname = fname; /* remember full fname */ | |
3164 #ifdef UNIX | |
3165 fname = sfname; | |
3166 #endif | |
3167 | |
3168 if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0) | |
3169 overwriting = TRUE; | |
3170 else | |
3171 overwriting = FALSE; | |
3172 | |
3173 if (exiting) | |
3174 settmode(TMODE_COOK); /* when exiting allow typeahead now */ | |
3175 | |
3176 ++no_wait_return; /* don't wait for return yet */ | |
3177 | |
3178 /* | |
3179 * Set '[ and '] marks to the lines to be written. | |
3180 */ | |
3181 buf->b_op_start.lnum = start; | |
3182 buf->b_op_start.col = 0; | |
3183 buf->b_op_end.lnum = end; | |
3184 buf->b_op_end.col = 0; | |
3185 | |
3186 { | |
3187 aco_save_T aco; | |
3188 int buf_ffname = FALSE; | |
3189 int buf_sfname = FALSE; | |
3190 int buf_fname_f = FALSE; | |
3191 int buf_fname_s = FALSE; | |
3192 int did_cmd = FALSE; | |
3193 int nofile_err = FALSE; | |
3194 int empty_memline = (buf->b_ml.ml_mfp == NULL); | |
3195 bufref_T bufref; | |
3196 | |
3197 /* | |
3198 * Apply PRE autocommands. | |
3199 * Set curbuf to the buffer to be written. | |
3200 * Careful: The autocommands may call buf_write() recursively! | |
3201 */ | |
3202 if (ffname == buf->b_ffname) | |
3203 buf_ffname = TRUE; | |
3204 if (sfname == buf->b_sfname) | |
3205 buf_sfname = TRUE; | |
3206 if (fname == buf->b_ffname) | |
3207 buf_fname_f = TRUE; | |
3208 if (fname == buf->b_sfname) | |
3209 buf_fname_s = TRUE; | |
3210 | |
3211 /* set curwin/curbuf to buf and save a few things */ | |
3212 aucmd_prepbuf(&aco, buf); | |
3213 set_bufref(&bufref, buf); | |
3214 | |
3215 if (append) | |
3216 { | |
3217 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, | |
3218 sfname, sfname, FALSE, curbuf, eap))) | |
3219 { | |
3220 #ifdef FEAT_QUICKFIX | |
3221 if (overwriting && bt_nofilename(curbuf)) | |
3222 nofile_err = TRUE; | |
3223 else | |
3224 #endif | |
3225 apply_autocmds_exarg(EVENT_FILEAPPENDPRE, | |
3226 sfname, sfname, FALSE, curbuf, eap); | |
3227 } | |
3228 } | |
3229 else if (filtering) | |
3230 { | |
3231 apply_autocmds_exarg(EVENT_FILTERWRITEPRE, | |
3232 NULL, sfname, FALSE, curbuf, eap); | |
3233 } | |
3234 else if (reset_changed && whole) | |
3235 { | |
3236 int was_changed = curbufIsChanged(); | |
3237 | |
3238 did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, | |
3239 sfname, sfname, FALSE, curbuf, eap); | |
3240 if (did_cmd) | |
3241 { | |
3242 if (was_changed && !curbufIsChanged()) | |
3243 { | |
3244 /* Written everything correctly and BufWriteCmd has reset | |
3245 * 'modified': Correct the undo information so that an | |
3246 * undo now sets 'modified'. */ | |
3247 u_unchanged(curbuf); | |
3248 u_update_save_nr(curbuf); | |
3249 } | |
3250 } | |
3251 else | |
3252 { | |
3253 #ifdef FEAT_QUICKFIX | |
3254 if (overwriting && bt_nofilename(curbuf)) | |
3255 nofile_err = TRUE; | |
3256 else | |
3257 #endif | |
3258 apply_autocmds_exarg(EVENT_BUFWRITEPRE, | |
3259 sfname, sfname, FALSE, curbuf, eap); | |
3260 } | |
3261 } | |
3262 else | |
3263 { | |
3264 if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, | |
3265 sfname, sfname, FALSE, curbuf, eap))) | |
3266 { | |
3267 #ifdef FEAT_QUICKFIX | |
3268 if (overwriting && bt_nofilename(curbuf)) | |
3269 nofile_err = TRUE; | |
3270 else | |
3271 #endif | |
3272 apply_autocmds_exarg(EVENT_FILEWRITEPRE, | |
3273 sfname, sfname, FALSE, curbuf, eap); | |
3274 } | |
3275 } | |
3276 | |
3277 /* restore curwin/curbuf and a few other things */ | |
3278 aucmd_restbuf(&aco); | |
3279 | |
3280 /* | |
3281 * In three situations we return here and don't write the file: | |
3282 * 1. the autocommands deleted or unloaded the buffer. | |
3283 * 2. The autocommands abort script processing. | |
3284 * 3. If one of the "Cmd" autocommands was executed. | |
3285 */ | |
3286 if (!bufref_valid(&bufref)) | |
3287 buf = NULL; | |
3288 if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) | |
3289 || did_cmd || nofile_err | |
3290 #ifdef FEAT_EVAL | |
3291 || aborting() | |
3292 #endif | |
3293 ) | |
3294 { | |
3295 --no_wait_return; | |
3296 msg_scroll = msg_save; | |
3297 if (nofile_err) | |
3298 emsg(_("E676: No matching autocommands for acwrite buffer")); | |
3299 | |
3300 if (nofile_err | |
3301 #ifdef FEAT_EVAL | |
3302 || aborting() | |
3303 #endif | |
3304 ) | |
3305 /* An aborting error, interrupt or exception in the | |
3306 * autocommands. */ | |
3307 return FAIL; | |
3308 if (did_cmd) | |
3309 { | |
3310 if (buf == NULL) | |
3311 /* The buffer was deleted. We assume it was written | |
3312 * (can't retry anyway). */ | |
3313 return OK; | |
3314 if (overwriting) | |
3315 { | |
3316 /* Assume the buffer was written, update the timestamp. */ | |
3317 ml_timestamp(buf); | |
3318 if (append) | |
3319 buf->b_flags &= ~BF_NEW; | |
3320 else | |
3321 buf->b_flags &= ~BF_WRITE_MASK; | |
3322 } | |
3323 if (reset_changed && buf->b_changed && !append | |
3324 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) | |
3325 /* Buffer still changed, the autocommands didn't work | |
3326 * properly. */ | |
3327 return FAIL; | |
3328 return OK; | |
3329 } | |
3330 #ifdef FEAT_EVAL | |
3331 if (!aborting()) | |
3332 #endif | |
3333 emsg(_("E203: Autocommands deleted or unloaded buffer to be written")); | |
3334 return FAIL; | |
3335 } | |
3336 | |
3337 /* | |
3338 * The autocommands may have changed the number of lines in the file. | |
3339 * When writing the whole file, adjust the end. | |
3340 * When writing part of the file, assume that the autocommands only | |
3341 * changed the number of lines that are to be written (tricky!). | |
3342 */ | |
3343 if (buf->b_ml.ml_line_count != old_line_count) | |
3344 { | |
3345 if (whole) /* write all */ | |
3346 end = buf->b_ml.ml_line_count; | |
3347 else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */ | |
3348 end += buf->b_ml.ml_line_count - old_line_count; | |
3349 else /* less lines */ | |
3350 { | |
3351 end -= old_line_count - buf->b_ml.ml_line_count; | |
3352 if (end < start) | |
3353 { | |
3354 --no_wait_return; | |
3355 msg_scroll = msg_save; | |
3356 emsg(_("E204: Autocommand changed number of lines in unexpected way")); | |
3357 return FAIL; | |
3358 } | |
3359 } | |
3360 } | |
3361 | |
3362 /* | |
3363 * The autocommands may have changed the name of the buffer, which may | |
3364 * be kept in fname, ffname and sfname. | |
3365 */ | |
3366 if (buf_ffname) | |
3367 ffname = buf->b_ffname; | |
3368 if (buf_sfname) | |
3369 sfname = buf->b_sfname; | |
3370 if (buf_fname_f) | |
3371 fname = buf->b_ffname; | |
3372 if (buf_fname_s) | |
3373 fname = buf->b_sfname; | |
3374 } | |
3375 | |
3376 #ifdef FEAT_NETBEANS_INTG | |
3377 if (netbeans_active() && isNetbeansBuffer(buf)) | |
3378 { | |
3379 if (whole) | |
3380 { | |
3381 /* | |
3382 * b_changed can be 0 after an undo, but we still need to write | |
3383 * the buffer to NetBeans. | |
3384 */ | |
3385 if (buf->b_changed || isNetbeansModified(buf)) | |
3386 { | |
3387 --no_wait_return; /* may wait for return now */ | |
3388 msg_scroll = msg_save; | |
3389 netbeans_save_buffer(buf); /* no error checking... */ | |
3390 return retval; | |
3391 } | |
3392 else | |
3393 { | |
3394 errnum = (char_u *)"E656: "; | |
3395 errmsg = (char_u *)_("NetBeans disallows writes of unmodified buffers"); | |
3396 buffer = NULL; | |
3397 goto fail; | |
3398 } | |
3399 } | |
3400 else | |
3401 { | |
3402 errnum = (char_u *)"E657: "; | |
3403 errmsg = (char_u *)_("Partial writes disallowed for NetBeans buffers"); | |
3404 buffer = NULL; | |
3405 goto fail; | |
3406 } | |
3407 } | |
3408 #endif | |
3409 | |
3410 if (shortmess(SHM_OVER) && !exiting) | |
3411 msg_scroll = FALSE; /* overwrite previous file message */ | |
3412 else | |
3413 msg_scroll = TRUE; /* don't overwrite previous file message */ | |
3414 if (!filtering) | |
3415 filemess(buf, | |
3416 #ifndef UNIX | |
3417 sfname, | |
3418 #else | |
3419 fname, | |
3420 #endif | |
3421 (char_u *)"", 0); /* show that we are busy */ | |
3422 msg_scroll = FALSE; /* always overwrite the file message now */ | |
3423 | |
3424 buffer = alloc(BUFSIZE); | |
3425 if (buffer == NULL) /* can't allocate big buffer, use small | |
3426 * one (to be able to write when out of | |
3427 * memory) */ | |
3428 { | |
3429 buffer = smallbuf; | |
3430 bufsize = SMBUFSIZE; | |
3431 } | |
3432 else | |
3433 bufsize = BUFSIZE; | |
3434 | |
3435 /* | |
3436 * Get information about original file (if there is one). | |
3437 */ | |
3438 #if defined(UNIX) | |
3439 st_old.st_dev = 0; | |
3440 st_old.st_ino = 0; | |
3441 perm = -1; | |
3442 if (mch_stat((char *)fname, &st_old) < 0) | |
3443 newfile = TRUE; | |
3444 else | |
3445 { | |
3446 perm = st_old.st_mode; | |
3447 if (!S_ISREG(st_old.st_mode)) /* not a file */ | |
3448 { | |
3449 if (S_ISDIR(st_old.st_mode)) | |
3450 { | |
3451 errnum = (char_u *)"E502: "; | |
3452 errmsg = (char_u *)_("is a directory"); | |
3453 goto fail; | |
3454 } | |
3455 if (mch_nodetype(fname) != NODE_WRITABLE) | |
3456 { | |
3457 errnum = (char_u *)"E503: "; | |
3458 errmsg = (char_u *)_("is not a file or writable device"); | |
3459 goto fail; | |
3460 } | |
3461 /* It's a device of some kind (or a fifo) which we can write to | |
3462 * but for which we can't make a backup. */ | |
3463 device = TRUE; | |
3464 newfile = TRUE; | |
3465 perm = -1; | |
3466 } | |
3467 } | |
3468 #else /* !UNIX */ | |
3469 /* | |
3470 * Check for a writable device name. | |
3471 */ | |
3472 c = mch_nodetype(fname); | |
3473 if (c == NODE_OTHER) | |
3474 { | |
3475 errnum = (char_u *)"E503: "; | |
3476 errmsg = (char_u *)_("is not a file or writable device"); | |
3477 goto fail; | |
3478 } | |
3479 if (c == NODE_WRITABLE) | |
3480 { | |
3481 # if defined(MSWIN) | |
3482 /* MS-Windows allows opening a device, but we will probably get stuck | |
3483 * trying to write to it. */ | |
3484 if (!p_odev) | |
3485 { | |
3486 errnum = (char_u *)"E796: "; | |
3487 errmsg = (char_u *)_("writing to device disabled with 'opendevice' option"); | |
3488 goto fail; | |
3489 } | |
3490 # endif | |
3491 device = TRUE; | |
3492 newfile = TRUE; | |
3493 perm = -1; | |
3494 } | |
3495 else | |
3496 { | |
3497 perm = mch_getperm(fname); | |
3498 if (perm < 0) | |
3499 newfile = TRUE; | |
3500 else if (mch_isdir(fname)) | |
3501 { | |
3502 errnum = (char_u *)"E502: "; | |
3503 errmsg = (char_u *)_("is a directory"); | |
3504 goto fail; | |
3505 } | |
3506 if (overwriting) | |
3507 (void)mch_stat((char *)fname, &st_old); | |
3508 } | |
3509 #endif /* !UNIX */ | |
3510 | |
3511 if (!device && !newfile) | |
3512 { | |
3513 /* | |
3514 * Check if the file is really writable (when renaming the file to | |
3515 * make a backup we won't discover it later). | |
3516 */ | |
3517 file_readonly = check_file_readonly(fname, (int)perm); | |
3518 | |
3519 if (!forceit && file_readonly) | |
3520 { | |
3521 if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) | |
3522 { | |
3523 errnum = (char_u *)"E504: "; | |
3524 errmsg = (char_u *)_(err_readonly); | |
3525 } | |
3526 else | |
3527 { | |
3528 errnum = (char_u *)"E505: "; | |
3529 errmsg = (char_u *)_("is read-only (add ! to override)"); | |
3530 } | |
3531 goto fail; | |
3532 } | |
3533 | |
3534 /* | |
3535 * Check if the timestamp hasn't changed since reading the file. | |
3536 */ | |
3537 if (overwriting) | |
3538 { | |
3539 retval = check_mtime(buf, &st_old); | |
3540 if (retval == FAIL) | |
3541 goto fail; | |
3542 } | |
3543 } | |
3544 | |
3545 #ifdef HAVE_ACL | |
3546 /* | |
3547 * For systems that support ACL: get the ACL from the original file. | |
3548 */ | |
3549 if (!newfile) | |
3550 acl = mch_get_acl(fname); | |
3551 #endif | |
3552 | |
3553 /* | |
3554 * If 'backupskip' is not empty, don't make a backup for some files. | |
3555 */ | |
3556 dobackup = (p_wb || p_bk || *p_pm != NUL); | |
3557 #ifdef FEAT_WILDIGN | |
3558 if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) | |
3559 dobackup = FALSE; | |
3560 #endif | |
3561 | |
3562 /* | |
3563 * Save the value of got_int and reset it. We don't want a previous | |
3564 * interruption cancel writing, only hitting CTRL-C while writing should | |
3565 * abort it. | |
3566 */ | |
3567 prev_got_int = got_int; | |
3568 got_int = FALSE; | |
3569 | |
3570 /* Mark the buffer as 'being saved' to prevent changed buffer warnings */ | |
3571 buf->b_saving = TRUE; | |
3572 | |
3573 /* | |
3574 * If we are not appending or filtering, the file exists, and the | |
3575 * 'writebackup', 'backup' or 'patchmode' option is set, need a backup. | |
3576 * When 'patchmode' is set also make a backup when appending. | |
3577 * | |
3578 * Do not make any backup, if 'writebackup' and 'backup' are both switched | |
3579 * off. This helps when editing large files on almost-full disks. | |
3580 */ | |
3581 if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) | |
3582 { | |
3583 #if defined(UNIX) || defined(MSWIN) | |
3584 stat_T st; | |
3585 #endif | |
3586 | |
3587 if ((bkc & BKC_YES) || append) /* "yes" */ | |
3588 backup_copy = TRUE; | |
3589 #if defined(UNIX) || defined(MSWIN) | |
3590 else if ((bkc & BKC_AUTO)) /* "auto" */ | |
3591 { | |
3592 int i; | |
3593 | |
3594 # ifdef UNIX | |
3595 /* | |
3596 * Don't rename the file when: | |
3597 * - it's a hard link | |
3598 * - it's a symbolic link | |
3599 * - we don't have write permission in the directory | |
3600 * - we can't set the owner/group of the new file | |
3601 */ | |
3602 if (st_old.st_nlink > 1 | |
3603 || mch_lstat((char *)fname, &st) < 0 | |
3604 || st.st_dev != st_old.st_dev | |
3605 || st.st_ino != st_old.st_ino | |
3606 # ifndef HAVE_FCHOWN | |
3607 || st.st_uid != st_old.st_uid | |
3608 || st.st_gid != st_old.st_gid | |
3609 # endif | |
3610 ) | |
3611 backup_copy = TRUE; | |
3612 else | |
3613 # else | |
3614 # ifdef MSWIN | |
3615 /* On NTFS file systems hard links are possible. */ | |
3616 if (mch_is_linked(fname)) | |
3617 backup_copy = TRUE; | |
3618 else | |
3619 # endif | |
3620 # endif | |
3621 { | |
3622 /* | |
3623 * Check if we can create a file and set the owner/group to | |
3624 * the ones from the original file. | |
3625 * First find a file name that doesn't exist yet (use some | |
3626 * arbitrary numbers). | |
3627 */ | |
3628 STRCPY(IObuff, fname); | |
3629 for (i = 4913; ; i += 123) | |
3630 { | |
3631 sprintf((char *)gettail(IObuff), "%d", i); | |
3632 if (mch_lstat((char *)IObuff, &st) < 0) | |
3633 break; | |
3634 } | |
3635 fd = mch_open((char *)IObuff, | |
3636 O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm); | |
3637 if (fd < 0) /* can't write in directory */ | |
3638 backup_copy = TRUE; | |
3639 else | |
3640 { | |
3641 # ifdef UNIX | |
3642 # ifdef HAVE_FCHOWN | |
3643 vim_ignored = fchown(fd, st_old.st_uid, st_old.st_gid); | |
3644 # endif | |
3645 if (mch_stat((char *)IObuff, &st) < 0 | |
3646 || st.st_uid != st_old.st_uid | |
3647 || st.st_gid != st_old.st_gid | |
3648 || (long)st.st_mode != perm) | |
3649 backup_copy = TRUE; | |
3650 # endif | |
3651 /* Close the file before removing it, on MS-Windows we | |
3652 * can't delete an open file. */ | |
3653 close(fd); | |
3654 mch_remove(IObuff); | |
3655 # ifdef MSWIN | |
3656 /* MS-Windows may trigger a virus scanner to open the | |
3657 * file, we can't delete it then. Keep trying for half a | |
3658 * second. */ | |
3659 { | |
3660 int try; | |
3661 | |
3662 for (try = 0; try < 10; ++try) | |
3663 { | |
3664 if (mch_lstat((char *)IObuff, &st) < 0) | |
3665 break; | |
3666 ui_delay(50L, TRUE); /* wait 50 msec */ | |
3667 mch_remove(IObuff); | |
3668 } | |
3669 } | |
3670 # endif | |
3671 } | |
3672 } | |
3673 } | |
3674 | |
3675 /* | |
3676 * Break symlinks and/or hardlinks if we've been asked to. | |
3677 */ | |
3678 if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK)) | |
3679 { | |
3680 # ifdef UNIX | |
3681 int lstat_res; | |
3682 | |
3683 lstat_res = mch_lstat((char *)fname, &st); | |
3684 | |
3685 /* Symlinks. */ | |
3686 if ((bkc & BKC_BREAKSYMLINK) | |
3687 && lstat_res == 0 | |
3688 && st.st_ino != st_old.st_ino) | |
3689 backup_copy = FALSE; | |
3690 | |
3691 /* Hardlinks. */ | |
3692 if ((bkc & BKC_BREAKHARDLINK) | |
3693 && st_old.st_nlink > 1 | |
3694 && (lstat_res != 0 || st.st_ino == st_old.st_ino)) | |
3695 backup_copy = FALSE; | |
3696 # else | |
3697 # if defined(MSWIN) | |
3698 /* Symlinks. */ | |
3699 if ((bkc & BKC_BREAKSYMLINK) && mch_is_symbolic_link(fname)) | |
3700 backup_copy = FALSE; | |
3701 | |
3702 /* Hardlinks. */ | |
3703 if ((bkc & BKC_BREAKHARDLINK) && mch_is_hard_link(fname)) | |
3704 backup_copy = FALSE; | |
3705 # endif | |
3706 # endif | |
3707 } | |
3708 | |
3709 #endif | |
3710 | |
3711 /* make sure we have a valid backup extension to use */ | |
3712 if (*p_bex == NUL) | |
3713 backup_ext = (char_u *)".bak"; | |
3714 else | |
3715 backup_ext = p_bex; | |
3716 | |
3717 if (backup_copy | |
3718 && (fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0) | |
3719 { | |
3720 int bfd; | |
3721 char_u *copybuf, *wp; | |
3722 int some_error = FALSE; | |
3723 stat_T st_new; | |
3724 char_u *dirp; | |
3725 char_u *rootname; | |
3726 #if defined(UNIX) || defined(MSWIN) | |
3727 char_u *p; | |
3728 #endif | |
3729 #if defined(UNIX) | |
3730 int did_set_shortname; | |
3731 mode_t umask_save; | |
3732 #endif | |
3733 | |
3734 copybuf = alloc(BUFSIZE + 1); | |
3735 if (copybuf == NULL) | |
3736 { | |
3737 some_error = TRUE; /* out of memory */ | |
3738 goto nobackup; | |
3739 } | |
3740 | |
3741 /* | |
3742 * Try to make the backup in each directory in the 'bdir' option. | |
3743 * | |
3744 * Unix semantics has it, that we may have a writable file, | |
3745 * that cannot be recreated with a simple open(..., O_CREAT, ) e.g: | |
3746 * - the directory is not writable, | |
3747 * - the file may be a symbolic link, | |
3748 * - the file may belong to another user/group, etc. | |
3749 * | |
3750 * For these reasons, the existing writable file must be truncated | |
3751 * and reused. Creation of a backup COPY will be attempted. | |
3752 */ | |
3753 dirp = p_bdir; | |
3754 while (*dirp) | |
3755 { | |
3756 #ifdef UNIX | |
3757 st_new.st_ino = 0; | |
3758 st_new.st_dev = 0; | |
3759 st_new.st_gid = 0; | |
3760 #endif | |
3761 | |
3762 /* | |
3763 * Isolate one directory name, using an entry in 'bdir'. | |
3764 */ | |
3765 (void)copy_option_part(&dirp, copybuf, BUFSIZE, ","); | |
3766 | |
3767 #if defined(UNIX) || defined(MSWIN) | |
3768 p = copybuf + STRLEN(copybuf); | |
3769 if (after_pathsep(copybuf, p) && p[-1] == p[-2]) | |
3770 // Ends with '//', use full path | |
3771 if ((p = make_percent_swname(copybuf, fname)) != NULL) | |
3772 { | |
3773 backup = modname(p, backup_ext, FALSE); | |
3774 vim_free(p); | |
3775 } | |
3776 #endif | |
3777 rootname = get_file_in_dir(fname, copybuf); | |
3778 if (rootname == NULL) | |
3779 { | |
3780 some_error = TRUE; /* out of memory */ | |
3781 goto nobackup; | |
3782 } | |
3783 | |
3784 #if defined(UNIX) | |
3785 did_set_shortname = FALSE; | |
3786 #endif | |
3787 | |
3788 /* | |
3789 * May try twice if 'shortname' not set. | |
3790 */ | |
3791 for (;;) | |
3792 { | |
3793 /* | |
3794 * Make the backup file name. | |
3795 */ | |
3796 if (backup == NULL) | |
3797 backup = buf_modname((buf->b_p_sn || buf->b_shortname), | |
3798 rootname, backup_ext, FALSE); | |
3799 if (backup == NULL) | |
3800 { | |
3801 vim_free(rootname); | |
3802 some_error = TRUE; /* out of memory */ | |
3803 goto nobackup; | |
3804 } | |
3805 | |
3806 /* | |
3807 * Check if backup file already exists. | |
3808 */ | |
3809 if (mch_stat((char *)backup, &st_new) >= 0) | |
3810 { | |
3811 #ifdef UNIX | |
3812 /* | |
3813 * Check if backup file is same as original file. | |
3814 * May happen when modname() gave the same file back. | |
3815 * E.g. silly link, or file name-length reached. | |
3816 * If we don't check here, we either ruin the file | |
3817 * when copying or erase it after writing. jw. | |
3818 */ | |
3819 if (st_new.st_dev == st_old.st_dev | |
3820 && st_new.st_ino == st_old.st_ino) | |
3821 { | |
3822 VIM_CLEAR(backup); /* no backup file to delete */ | |
3823 /* | |
3824 * may try again with 'shortname' set | |
3825 */ | |
3826 if (!(buf->b_shortname || buf->b_p_sn)) | |
3827 { | |
3828 buf->b_shortname = TRUE; | |
3829 did_set_shortname = TRUE; | |
3830 continue; | |
3831 } | |
3832 /* setting shortname didn't help */ | |
3833 if (did_set_shortname) | |
3834 buf->b_shortname = FALSE; | |
3835 break; | |
3836 } | |
3837 #endif | |
3838 | |
3839 /* | |
3840 * If we are not going to keep the backup file, don't | |
3841 * delete an existing one, try to use another name. | |
3842 * Change one character, just before the extension. | |
3843 */ | |
3844 if (!p_bk) | |
3845 { | |
3846 wp = backup + STRLEN(backup) - 1 | |
3847 - STRLEN(backup_ext); | |
3848 if (wp < backup) /* empty file name ??? */ | |
3849 wp = backup; | |
3850 *wp = 'z'; | |
3851 while (*wp > 'a' | |
3852 && mch_stat((char *)backup, &st_new) >= 0) | |
3853 --*wp; | |
3854 /* They all exist??? Must be something wrong. */ | |
3855 if (*wp == 'a') | |
3856 VIM_CLEAR(backup); | |
3857 } | |
3858 } | |
3859 break; | |
3860 } | |
3861 vim_free(rootname); | |
3862 | |
3863 /* | |
3864 * Try to create the backup file | |
3865 */ | |
3866 if (backup != NULL) | |
3867 { | |
3868 /* remove old backup, if present */ | |
3869 mch_remove(backup); | |
3870 /* Open with O_EXCL to avoid the file being created while | |
3871 * we were sleeping (symlink hacker attack?). Reset umask | |
3872 * if possible to avoid mch_setperm() below. */ | |
3873 #ifdef UNIX | |
3874 umask_save = umask(0); | |
3875 #endif | |
3876 bfd = mch_open((char *)backup, | |
3877 O_WRONLY|O_CREAT|O_EXTRA|O_EXCL|O_NOFOLLOW, | |
3878 perm & 0777); | |
3879 #ifdef UNIX | |
3880 (void)umask(umask_save); | |
3881 #endif | |
3882 if (bfd < 0) | |
3883 VIM_CLEAR(backup); | |
3884 else | |
3885 { | |
3886 /* Set file protection same as original file, but | |
3887 * strip s-bit. Only needed if umask() wasn't used | |
3888 * above. */ | |
3889 #ifndef UNIX | |
3890 (void)mch_setperm(backup, perm & 0777); | |
3891 #else | |
3892 /* | |
3893 * Try to set the group of the backup same as the | |
3894 * original file. If this fails, set the protection | |
3895 * bits for the group same as the protection bits for | |
3896 * others. | |
3897 */ | |
3898 if (st_new.st_gid != st_old.st_gid | |
3899 # ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */ | |
3900 && fchown(bfd, (uid_t)-1, st_old.st_gid) != 0 | |
3901 # endif | |
3902 ) | |
3903 mch_setperm(backup, | |
3904 (perm & 0707) | ((perm & 07) << 3)); | |
3905 # if defined(HAVE_SELINUX) || defined(HAVE_SMACK) | |
3906 mch_copy_sec(fname, backup); | |
3907 # endif | |
3908 #endif | |
3909 | |
3910 /* | |
3911 * copy the file. | |
3912 */ | |
3913 write_info.bw_fd = bfd; | |
3914 write_info.bw_buf = copybuf; | |
3915 #ifdef HAS_BW_FLAGS | |
3916 write_info.bw_flags = FIO_NOCONVERT; | |
3917 #endif | |
3918 while ((write_info.bw_len = read_eintr(fd, copybuf, | |
3919 BUFSIZE)) > 0) | |
3920 { | |
3921 if (buf_write_bytes(&write_info) == FAIL) | |
3922 { | |
3923 errmsg = (char_u *)_("E506: Can't write to backup file (add ! to override)"); | |
3924 break; | |
3925 } | |
3926 ui_breakcheck(); | |
3927 if (got_int) | |
3928 { | |
3929 errmsg = (char_u *)_(e_interr); | |
3930 break; | |
3931 } | |
3932 } | |
3933 | |
3934 if (close(bfd) < 0 && errmsg == NULL) | |
3935 errmsg = (char_u *)_("E507: Close error for backup file (add ! to override)"); | |
3936 if (write_info.bw_len < 0) | |
3937 errmsg = (char_u *)_("E508: Can't read file for backup (add ! to override)"); | |
3938 #ifdef UNIX | |
3939 set_file_time(backup, st_old.st_atime, st_old.st_mtime); | |
3940 #endif | |
3941 #ifdef HAVE_ACL | |
3942 mch_set_acl(backup, acl); | |
3943 #endif | |
3944 #if defined(HAVE_SELINUX) || defined(HAVE_SMACK) | |
3945 mch_copy_sec(fname, backup); | |
3946 #endif | |
3947 break; | |
3948 } | |
3949 } | |
3950 } | |
3951 nobackup: | |
3952 close(fd); /* ignore errors for closing read file */ | |
3953 vim_free(copybuf); | |
3954 | |
3955 if (backup == NULL && errmsg == NULL) | |
3956 errmsg = (char_u *)_("E509: Cannot create backup file (add ! to override)"); | |
3957 /* ignore errors when forceit is TRUE */ | |
3958 if ((some_error || errmsg != NULL) && !forceit) | |
3959 { | |
3960 retval = FAIL; | |
3961 goto fail; | |
3962 } | |
3963 errmsg = NULL; | |
3964 } | |
3965 else | |
3966 { | |
3967 char_u *dirp; | |
3968 char_u *p; | |
3969 char_u *rootname; | |
3970 | |
3971 /* | |
3972 * Make a backup by renaming the original file. | |
3973 */ | |
3974 /* | |
3975 * If 'cpoptions' includes the "W" flag, we don't want to | |
3976 * overwrite a read-only file. But rename may be possible | |
3977 * anyway, thus we need an extra check here. | |
3978 */ | |
3979 if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) | |
3980 { | |
3981 errnum = (char_u *)"E504: "; | |
3982 errmsg = (char_u *)_(err_readonly); | |
3983 goto fail; | |
3984 } | |
3985 | |
3986 /* | |
3987 * | |
3988 * Form the backup file name - change path/fo.o.h to | |
3989 * path/fo.o.h.bak Try all directories in 'backupdir', first one | |
3990 * that works is used. | |
3991 */ | |
3992 dirp = p_bdir; | |
3993 while (*dirp) | |
3994 { | |
3995 /* | |
3996 * Isolate one directory name and make the backup file name. | |
3997 */ | |
3998 (void)copy_option_part(&dirp, IObuff, IOSIZE, ","); | |
3999 | |
4000 #if defined(UNIX) || defined(MSWIN) | |
4001 p = IObuff + STRLEN(IObuff); | |
4002 if (after_pathsep(IObuff, p) && p[-1] == p[-2]) | |
4003 // path ends with '//', use full path | |
4004 if ((p = make_percent_swname(IObuff, fname)) != NULL) | |
4005 { | |
4006 backup = modname(p, backup_ext, FALSE); | |
4007 vim_free(p); | |
4008 } | |
4009 #endif | |
4010 if (backup == NULL) | |
4011 { | |
4012 rootname = get_file_in_dir(fname, IObuff); | |
4013 if (rootname == NULL) | |
4014 backup = NULL; | |
4015 else | |
4016 { | |
4017 backup = buf_modname( | |
4018 (buf->b_p_sn || buf->b_shortname), | |
4019 rootname, backup_ext, FALSE); | |
4020 vim_free(rootname); | |
4021 } | |
4022 } | |
4023 | |
4024 if (backup != NULL) | |
4025 { | |
4026 /* | |
4027 * If we are not going to keep the backup file, don't | |
4028 * delete an existing one, try to use another name. | |
4029 * Change one character, just before the extension. | |
4030 */ | |
4031 if (!p_bk && mch_getperm(backup) >= 0) | |
4032 { | |
4033 p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); | |
4034 if (p < backup) /* empty file name ??? */ | |
4035 p = backup; | |
4036 *p = 'z'; | |
4037 while (*p > 'a' && mch_getperm(backup) >= 0) | |
4038 --*p; | |
4039 /* They all exist??? Must be something wrong! */ | |
4040 if (*p == 'a') | |
4041 VIM_CLEAR(backup); | |
4042 } | |
4043 } | |
4044 if (backup != NULL) | |
4045 { | |
4046 /* | |
4047 * Delete any existing backup and move the current version | |
4048 * to the backup. For safety, we don't remove the backup | |
4049 * until the write has finished successfully. And if the | |
4050 * 'backup' option is set, leave it around. | |
4051 */ | |
4052 /* | |
4053 * If the renaming of the original file to the backup file | |
4054 * works, quit here. | |
4055 */ | |
4056 if (vim_rename(fname, backup) == 0) | |
4057 break; | |
4058 | |
4059 VIM_CLEAR(backup); /* don't do the rename below */ | |
4060 } | |
4061 } | |
4062 if (backup == NULL && !forceit) | |
4063 { | |
4064 errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)"); | |
4065 goto fail; | |
4066 } | |
4067 } | |
4068 } | |
4069 | |
4070 #if defined(UNIX) | |
4071 /* When using ":w!" and the file was read-only: make it writable */ | |
4072 if (forceit && perm >= 0 && !(perm & 0200) && st_old.st_uid == getuid() | |
4073 && vim_strchr(p_cpo, CPO_FWRITE) == NULL) | |
4074 { | |
4075 perm |= 0200; | |
4076 (void)mch_setperm(fname, perm); | |
4077 made_writable = TRUE; | |
4078 } | |
4079 #endif | |
4080 | |
4081 /* When using ":w!" and writing to the current file, 'readonly' makes no | |
4082 * sense, reset it, unless 'Z' appears in 'cpoptions'. */ | |
4083 if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL) | |
4084 { | |
4085 buf->b_p_ro = FALSE; | |
4086 #ifdef FEAT_TITLE | |
4087 need_maketitle = TRUE; /* set window title later */ | |
4088 #endif | |
4089 status_redraw_all(); /* redraw status lines later */ | |
4090 } | |
4091 | |
4092 if (end > buf->b_ml.ml_line_count) | |
4093 end = buf->b_ml.ml_line_count; | |
4094 if (buf->b_ml.ml_flags & ML_EMPTY) | |
4095 start = end + 1; | |
4096 | |
4097 /* | |
4098 * If the original file is being overwritten, there is a small chance that | |
4099 * we crash in the middle of writing. Therefore the file is preserved now. | |
4100 * This makes all block numbers positive so that recovery does not need | |
4101 * the original file. | |
4102 * Don't do this if there is a backup file and we are exiting. | |
4103 */ | |
4104 if (reset_changed && !newfile && overwriting | |
4105 && !(exiting && backup != NULL)) | |
4106 { | |
4107 ml_preserve(buf, FALSE); | |
4108 if (got_int) | |
4109 { | |
4110 errmsg = (char_u *)_(e_interr); | |
4111 goto restore_backup; | |
4112 } | |
4113 } | |
4114 | |
4115 #ifdef VMS | |
4116 vms_remove_version(fname); /* remove version */ | |
4117 #endif | |
4118 /* Default: write the file directly. May write to a temp file for | |
4119 * multi-byte conversion. */ | |
4120 wfname = fname; | |
4121 | |
4122 /* Check for forced 'fileencoding' from "++opt=val" argument. */ | |
4123 if (eap != NULL && eap->force_enc != 0) | |
4124 { | |
4125 fenc = eap->cmd + eap->force_enc; | |
4126 fenc = enc_canonize(fenc); | |
4127 fenc_tofree = fenc; | |
4128 } | |
4129 else | |
4130 fenc = buf->b_p_fenc; | |
4131 | |
4132 /* | |
4133 * Check if the file needs to be converted. | |
4134 */ | |
4135 converted = need_conversion(fenc); | |
4136 | |
4137 /* | |
4138 * Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or | |
4139 * Latin1 to Unicode conversion. This is handled in buf_write_bytes(). | |
4140 * Prepare the flags for it and allocate bw_conv_buf when needed. | |
4141 */ | |
4142 if (converted && (enc_utf8 || STRCMP(p_enc, "latin1") == 0)) | |
4143 { | |
4144 wb_flags = get_fio_flags(fenc); | |
4145 if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) | |
4146 { | |
4147 /* Need to allocate a buffer to translate into. */ | |
4148 if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) | |
4149 write_info.bw_conv_buflen = bufsize * 2; | |
4150 else /* FIO_UCS4 */ | |
4151 write_info.bw_conv_buflen = bufsize * 4; | |
4152 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); | |
4153 if (write_info.bw_conv_buf == NULL) | |
4154 end = 0; | |
4155 } | |
4156 } | |
4157 | |
4158 #ifdef MSWIN | |
4159 if (converted && wb_flags == 0 && (wb_flags = get_win_fio_flags(fenc)) != 0) | |
4160 { | |
4161 /* Convert UTF-8 -> UCS-2 and UCS-2 -> DBCS. Worst-case * 4: */ | |
4162 write_info.bw_conv_buflen = bufsize * 4; | |
4163 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); | |
4164 if (write_info.bw_conv_buf == NULL) | |
4165 end = 0; | |
4166 } | |
4167 #endif | |
4168 | |
4169 #ifdef MACOS_CONVERT | |
4170 if (converted && wb_flags == 0 && (wb_flags = get_mac_fio_flags(fenc)) != 0) | |
4171 { | |
4172 write_info.bw_conv_buflen = bufsize * 3; | |
4173 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); | |
4174 if (write_info.bw_conv_buf == NULL) | |
4175 end = 0; | |
4176 } | |
4177 #endif | |
4178 | |
4179 #if defined(FEAT_EVAL) || defined(USE_ICONV) | |
4180 if (converted && wb_flags == 0) | |
4181 { | |
4182 # ifdef USE_ICONV | |
4183 /* | |
4184 * Use iconv() conversion when conversion is needed and it's not done | |
4185 * internally. | |
4186 */ | |
4187 write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, | |
4188 enc_utf8 ? (char_u *)"utf-8" : p_enc); | |
4189 if (write_info.bw_iconv_fd != (iconv_t)-1) | |
4190 { | |
4191 /* We're going to use iconv(), allocate a buffer to convert in. */ | |
4192 write_info.bw_conv_buflen = bufsize * ICONV_MULT; | |
4193 write_info.bw_conv_buf = alloc(write_info.bw_conv_buflen); | |
4194 if (write_info.bw_conv_buf == NULL) | |
4195 end = 0; | |
4196 write_info.bw_first = TRUE; | |
4197 } | |
4198 # ifdef FEAT_EVAL | |
4199 else | |
4200 # endif | |
4201 # endif | |
4202 | |
4203 # ifdef FEAT_EVAL | |
4204 /* | |
4205 * When the file needs to be converted with 'charconvert' after | |
4206 * writing, write to a temp file instead and let the conversion | |
4207 * overwrite the original file. | |
4208 */ | |
4209 if (*p_ccv != NUL) | |
4210 { | |
4211 wfname = vim_tempname('w', FALSE); | |
4212 if (wfname == NULL) /* Can't write without a tempfile! */ | |
4213 { | |
4214 errmsg = (char_u *)_("E214: Can't find temp file for writing"); | |
4215 goto restore_backup; | |
4216 } | |
4217 } | |
4218 # endif | |
4219 } | |
4220 #endif | |
4221 if (converted && wb_flags == 0 | |
4222 #ifdef USE_ICONV | |
4223 && write_info.bw_iconv_fd == (iconv_t)-1 | |
4224 # endif | |
4225 # ifdef FEAT_EVAL | |
4226 && wfname == fname | |
4227 # endif | |
4228 ) | |
4229 { | |
4230 if (!forceit) | |
4231 { | |
4232 errmsg = (char_u *)_("E213: Cannot convert (add ! to write without conversion)"); | |
4233 goto restore_backup; | |
4234 } | |
4235 notconverted = TRUE; | |
4236 } | |
4237 | |
4238 /* | |
4239 * If conversion is taking place, we may first pretend to write and check | |
4240 * for conversion errors. Then loop again to write for real. | |
4241 * When not doing conversion this writes for real right away. | |
4242 */ | |
4243 for (checking_conversion = TRUE; ; checking_conversion = FALSE) | |
4244 { | |
4245 /* | |
4246 * There is no need to check conversion when: | |
4247 * - there is no conversion | |
4248 * - we make a backup file, that can be restored in case of conversion | |
4249 * failure. | |
4250 */ | |
4251 if (!converted || dobackup) | |
4252 checking_conversion = FALSE; | |
4253 | |
4254 if (checking_conversion) | |
4255 { | |
4256 /* Make sure we don't write anything. */ | |
4257 fd = -1; | |
4258 write_info.bw_fd = fd; | |
4259 } | |
4260 else | |
4261 { | |
4262 #ifdef HAVE_FTRUNCATE | |
4263 # define TRUNC_ON_OPEN 0 | |
4264 #else | |
4265 # define TRUNC_ON_OPEN O_TRUNC | |
4266 #endif | |
4267 /* | |
4268 * Open the file "wfname" for writing. | |
4269 * We may try to open the file twice: If we can't write to the file | |
4270 * and forceit is TRUE we delete the existing file and try to | |
4271 * create a new one. If this still fails we may have lost the | |
4272 * original file! (this may happen when the user reached his | |
4273 * quotum for number of files). | |
4274 * Appending will fail if the file does not exist and forceit is | |
4275 * FALSE. | |
4276 */ | |
4277 while ((fd = mch_open((char *)wfname, O_WRONLY | O_EXTRA | (append | |
4278 ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND) | |
4279 : (O_CREAT | TRUNC_ON_OPEN)) | |
4280 , perm < 0 ? 0666 : (perm & 0777))) < 0) | |
4281 { | |
4282 /* | |
4283 * A forced write will try to create a new file if the old one | |
4284 * is still readonly. This may also happen when the directory | |
4285 * is read-only. In that case the mch_remove() will fail. | |
4286 */ | |
4287 if (errmsg == NULL) | |
4288 { | |
4289 #ifdef UNIX | |
4290 stat_T st; | |
4291 | |
4292 /* Don't delete the file when it's a hard or symbolic link. | |
4293 */ | |
4294 if ((!newfile && st_old.st_nlink > 1) | |
4295 || (mch_lstat((char *)fname, &st) == 0 | |
4296 && (st.st_dev != st_old.st_dev | |
4297 || st.st_ino != st_old.st_ino))) | |
4298 errmsg = (char_u *)_("E166: Can't open linked file for writing"); | |
4299 else | |
4300 #endif | |
4301 { | |
4302 errmsg = (char_u *)_("E212: Can't open file for writing"); | |
4303 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL | |
4304 && perm >= 0) | |
4305 { | |
4306 #ifdef UNIX | |
4307 /* we write to the file, thus it should be marked | |
4308 writable after all */ | |
4309 if (!(perm & 0200)) | |
4310 made_writable = TRUE; | |
4311 perm |= 0200; | |
4312 if (st_old.st_uid != getuid() | |
4313 || st_old.st_gid != getgid()) | |
4314 perm &= 0777; | |
4315 #endif | |
4316 if (!append) /* don't remove when appending */ | |
4317 mch_remove(wfname); | |
4318 continue; | |
4319 } | |
4320 } | |
4321 } | |
4322 | |
4323 restore_backup: | |
4324 { | |
4325 stat_T st; | |
4326 | |
4327 /* | |
4328 * If we failed to open the file, we don't need a backup. | |
4329 * Throw it away. If we moved or removed the original file | |
4330 * try to put the backup in its place. | |
4331 */ | |
4332 if (backup != NULL && wfname == fname) | |
4333 { | |
4334 if (backup_copy) | |
4335 { | |
4336 /* | |
4337 * There is a small chance that we removed the | |
4338 * original, try to move the copy in its place. | |
4339 * This may not work if the vim_rename() fails. | |
4340 * In that case we leave the copy around. | |
4341 */ | |
4342 /* If file does not exist, put the copy in its | |
4343 * place */ | |
4344 if (mch_stat((char *)fname, &st) < 0) | |
4345 vim_rename(backup, fname); | |
4346 /* if original file does exist throw away the copy | |
4347 */ | |
4348 if (mch_stat((char *)fname, &st) >= 0) | |
4349 mch_remove(backup); | |
4350 } | |
4351 else | |
4352 { | |
4353 /* try to put the original file back */ | |
4354 vim_rename(backup, fname); | |
4355 } | |
4356 } | |
4357 | |
4358 /* if original file no longer exists give an extra warning | |
4359 */ | |
4360 if (!newfile && mch_stat((char *)fname, &st) < 0) | |
4361 end = 0; | |
4362 } | |
4363 | |
4364 if (wfname != fname) | |
4365 vim_free(wfname); | |
4366 goto fail; | |
4367 } | |
4368 write_info.bw_fd = fd; | |
4369 | |
4370 #if defined(UNIX) | |
4371 { | |
4372 stat_T st; | |
4373 | |
4374 /* Double check we are writing the intended file before making | |
4375 * any changes. */ | |
4376 if (overwriting | |
4377 && (!dobackup || backup_copy) | |
4378 && fname == wfname | |
4379 && perm >= 0 | |
4380 && mch_fstat(fd, &st) == 0 | |
4381 && st.st_ino != st_old.st_ino) | |
4382 { | |
4383 close(fd); | |
4384 errmsg = (char_u *)_("E949: File changed while writing"); | |
4385 goto fail; | |
4386 } | |
4387 } | |
4388 #endif | |
4389 #ifdef HAVE_FTRUNCATE | |
4390 if (!append) | |
4391 vim_ignored = ftruncate(fd, (off_t)0); | |
4392 #endif | |
4393 | |
4394 #if defined(MSWIN) | |
4395 if (backup != NULL && overwriting && !append) | |
4396 { | |
4397 if (backup_copy) | |
4398 (void)mch_copy_file_attribute(wfname, backup); | |
4399 else | |
4400 (void)mch_copy_file_attribute(backup, wfname); | |
4401 } | |
4402 | |
4403 if (!overwriting && !append) | |
4404 { | |
4405 if (buf->b_ffname != NULL) | |
4406 (void)mch_copy_file_attribute(buf->b_ffname, wfname); | |
4407 /* Should copy resource fork */ | |
4408 } | |
4409 #endif | |
4410 | |
4411 #ifdef FEAT_CRYPT | |
4412 if (*buf->b_p_key != NUL && !filtering) | |
4413 { | |
4414 char_u *header; | |
4415 int header_len; | |
4416 | |
4417 buf->b_cryptstate = crypt_create_for_writing( | |
4418 crypt_get_method_nr(buf), | |
4419 buf->b_p_key, &header, &header_len); | |
4420 if (buf->b_cryptstate == NULL || header == NULL) | |
4421 end = 0; | |
4422 else | |
4423 { | |
4424 /* Write magic number, so that Vim knows how this file is | |
4425 * encrypted when reading it back. */ | |
4426 write_info.bw_buf = header; | |
4427 write_info.bw_len = header_len; | |
4428 write_info.bw_flags = FIO_NOCONVERT; | |
4429 if (buf_write_bytes(&write_info) == FAIL) | |
4430 end = 0; | |
4431 wb_flags |= FIO_ENCRYPTED; | |
4432 vim_free(header); | |
4433 } | |
4434 } | |
4435 #endif | |
4436 } | |
4437 errmsg = NULL; | |
4438 | |
4439 write_info.bw_buf = buffer; | |
4440 nchars = 0; | |
4441 | |
4442 /* use "++bin", "++nobin" or 'binary' */ | |
4443 if (eap != NULL && eap->force_bin != 0) | |
4444 write_bin = (eap->force_bin == FORCE_BIN); | |
4445 else | |
4446 write_bin = buf->b_p_bin; | |
4447 | |
4448 /* | |
4449 * The BOM is written just after the encryption magic number. | |
4450 * Skip it when appending and the file already existed, the BOM only | |
4451 * makes sense at the start of the file. | |
4452 */ | |
4453 if (buf->b_p_bomb && !write_bin && (!append || perm < 0)) | |
4454 { | |
4455 write_info.bw_len = make_bom(buffer, fenc); | |
4456 if (write_info.bw_len > 0) | |
4457 { | |
4458 /* don't convert, do encryption */ | |
4459 write_info.bw_flags = FIO_NOCONVERT | wb_flags; | |
4460 if (buf_write_bytes(&write_info) == FAIL) | |
4461 end = 0; | |
4462 else | |
4463 nchars += write_info.bw_len; | |
4464 } | |
4465 } | |
4466 write_info.bw_start_lnum = start; | |
4467 | |
4468 #ifdef FEAT_PERSISTENT_UNDO | |
4469 write_undo_file = (buf->b_p_udf | |
4470 && overwriting | |
4471 && !append | |
4472 && !filtering | |
4473 && reset_changed | |
4474 && !checking_conversion); | |
4475 if (write_undo_file) | |
4476 /* Prepare for computing the hash value of the text. */ | |
4477 sha256_start(&sha_ctx); | |
4478 #endif | |
4479 | |
4480 write_info.bw_len = bufsize; | |
4481 #ifdef HAS_BW_FLAGS | |
4482 write_info.bw_flags = wb_flags; | |
4483 #endif | |
4484 fileformat = get_fileformat_force(buf, eap); | |
4485 s = buffer; | |
4486 len = 0; | |
4487 for (lnum = start; lnum <= end; ++lnum) | |
4488 { | |
4489 /* | |
4490 * The next while loop is done once for each character written. | |
4491 * Keep it fast! | |
4492 */ | |
4493 ptr = ml_get_buf(buf, lnum, FALSE) - 1; | |
4494 #ifdef FEAT_PERSISTENT_UNDO | |
4495 if (write_undo_file) | |
4496 sha256_update(&sha_ctx, ptr + 1, | |
4497 (UINT32_T)(STRLEN(ptr + 1) + 1)); | |
4498 #endif | |
4499 while ((c = *++ptr) != NUL) | |
4500 { | |
4501 if (c == NL) | |
4502 *s = NUL; /* replace newlines with NULs */ | |
4503 else if (c == CAR && fileformat == EOL_MAC) | |
4504 *s = NL; /* Mac: replace CRs with NLs */ | |
4505 else | |
4506 *s = c; | |
4507 ++s; | |
4508 if (++len != bufsize) | |
4509 continue; | |
4510 if (buf_write_bytes(&write_info) == FAIL) | |
4511 { | |
4512 end = 0; /* write error: break loop */ | |
4513 break; | |
4514 } | |
4515 nchars += bufsize; | |
4516 s = buffer; | |
4517 len = 0; | |
4518 write_info.bw_start_lnum = lnum; | |
4519 } | |
4520 /* write failed or last line has no EOL: stop here */ | |
4521 if (end == 0 | |
4522 || (lnum == end | |
4523 && (write_bin || !buf->b_p_fixeol) | |
4524 && (lnum == buf->b_no_eol_lnum | |
4525 || (lnum == buf->b_ml.ml_line_count | |
4526 && !buf->b_p_eol)))) | |
4527 { | |
4528 ++lnum; /* written the line, count it */ | |
4529 no_eol = TRUE; | |
4530 break; | |
4531 } | |
4532 if (fileformat == EOL_UNIX) | |
4533 *s++ = NL; | |
4534 else | |
4535 { | |
4536 *s++ = CAR; /* EOL_MAC or EOL_DOS: write CR */ | |
4537 if (fileformat == EOL_DOS) /* write CR-NL */ | |
4538 { | |
4539 if (++len == bufsize) | |
4540 { | |
4541 if (buf_write_bytes(&write_info) == FAIL) | |
4542 { | |
4543 end = 0; /* write error: break loop */ | |
4544 break; | |
4545 } | |
4546 nchars += bufsize; | |
4547 s = buffer; | |
4548 len = 0; | |
4549 } | |
4550 *s++ = NL; | |
4551 } | |
4552 } | |
4553 if (++len == bufsize && end) | |
4554 { | |
4555 if (buf_write_bytes(&write_info) == FAIL) | |
4556 { | |
4557 end = 0; /* write error: break loop */ | |
4558 break; | |
4559 } | |
4560 nchars += bufsize; | |
4561 s = buffer; | |
4562 len = 0; | |
4563 | |
4564 ui_breakcheck(); | |
4565 if (got_int) | |
4566 { | |
4567 end = 0; /* Interrupted, break loop */ | |
4568 break; | |
4569 } | |
4570 } | |
4571 #ifdef VMS | |
4572 /* | |
4573 * On VMS there is a problem: newlines get added when writing | |
4574 * blocks at a time. Fix it by writing a line at a time. | |
4575 * This is much slower! | |
4576 * Explanation: VAX/DECC RTL insists that records in some RMS | |
4577 * structures end with a newline (carriage return) character, and | |
4578 * if they don't it adds one. | |
4579 * With other RMS structures it works perfect without this fix. | |
4580 */ | |
4581 if (buf->b_fab_rfm == FAB$C_VFC | |
4582 || ((buf->b_fab_rat & (FAB$M_FTN | FAB$M_CR)) != 0)) | |
4583 { | |
4584 int b2write; | |
4585 | |
4586 buf->b_fab_mrs = (buf->b_fab_mrs == 0 | |
4587 ? MIN(4096, bufsize) | |
4588 : MIN(buf->b_fab_mrs, bufsize)); | |
4589 | |
4590 b2write = len; | |
4591 while (b2write > 0) | |
4592 { | |
4593 write_info.bw_len = MIN(b2write, buf->b_fab_mrs); | |
4594 if (buf_write_bytes(&write_info) == FAIL) | |
4595 { | |
4596 end = 0; | |
4597 break; | |
4598 } | |
4599 b2write -= MIN(b2write, buf->b_fab_mrs); | |
4600 } | |
4601 write_info.bw_len = bufsize; | |
4602 nchars += len; | |
4603 s = buffer; | |
4604 len = 0; | |
4605 } | |
4606 #endif | |
4607 } | |
4608 if (len > 0 && end > 0) | |
4609 { | |
4610 write_info.bw_len = len; | |
4611 if (buf_write_bytes(&write_info) == FAIL) | |
4612 end = 0; /* write error */ | |
4613 nchars += len; | |
4614 } | |
4615 | |
4616 /* Stop when writing done or an error was encountered. */ | |
4617 if (!checking_conversion || end == 0) | |
4618 break; | |
4619 | |
4620 /* If no error happened until now, writing should be ok, so loop to | |
4621 * really write the buffer. */ | |
4622 } | |
4623 | |
4624 /* If we started writing, finish writing. Also when an error was | |
4625 * encountered. */ | |
4626 if (!checking_conversion) | |
4627 { | |
4628 #if defined(UNIX) && defined(HAVE_FSYNC) | |
4629 /* | |
4630 * On many journalling file systems there is a bug that causes both the | |
4631 * original and the backup file to be lost when halting the system | |
4632 * right after writing the file. That's because only the meta-data is | |
4633 * journalled. Syncing the file slows down the system, but assures it | |
4634 * has been written to disk and we don't lose it. | |
4635 * For a device do try the fsync() but don't complain if it does not | |
4636 * work (could be a pipe). | |
4637 * If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. | |
4638 */ | |
4639 if (p_fs && vim_fsync(fd) != 0 && !device) | |
4640 { | |
4641 errmsg = (char_u *)_(e_fsync); | |
4642 end = 0; | |
4643 } | |
4644 #endif | |
4645 | |
4646 #if defined(HAVE_SELINUX) || defined(HAVE_SMACK) | |
4647 /* Probably need to set the security context. */ | |
4648 if (!backup_copy) | |
4649 mch_copy_sec(backup, wfname); | |
4650 #endif | |
4651 | |
4652 #ifdef UNIX | |
4653 /* When creating a new file, set its owner/group to that of the | |
4654 * original file. Get the new device and inode number. */ | |
4655 if (backup != NULL && !backup_copy) | |
4656 { | |
4657 # ifdef HAVE_FCHOWN | |
4658 stat_T st; | |
4659 | |
4660 /* Don't change the owner when it's already OK, some systems remove | |
4661 * permission or ACL stuff. */ | |
4662 if (mch_stat((char *)wfname, &st) < 0 | |
4663 || st.st_uid != st_old.st_uid | |
4664 || st.st_gid != st_old.st_gid) | |
4665 { | |
4666 /* changing owner might not be possible */ | |
4667 vim_ignored = fchown(fd, st_old.st_uid, -1); | |
4668 /* if changing group fails clear the group permissions */ | |
4669 if (fchown(fd, -1, st_old.st_gid) == -1 && perm > 0) | |
4670 perm &= ~070; | |
4671 } | |
4672 # endif | |
4673 buf_setino(buf); | |
4674 } | |
4675 else if (!buf->b_dev_valid) | |
4676 /* Set the inode when creating a new file. */ | |
4677 buf_setino(buf); | |
4678 #endif | |
4679 | |
4680 #ifdef UNIX | |
4681 if (made_writable) | |
4682 perm &= ~0200; /* reset 'w' bit for security reasons */ | |
4683 #endif | |
4684 #ifdef HAVE_FCHMOD | |
4685 /* set permission of new file same as old file */ | |
4686 if (perm >= 0) | |
4687 (void)mch_fsetperm(fd, perm); | |
4688 #endif | |
4689 if (close(fd) != 0) | |
4690 { | |
4691 errmsg = (char_u *)_("E512: Close failed"); | |
4692 end = 0; | |
4693 } | |
4694 | |
4695 #ifndef HAVE_FCHMOD | |
4696 /* set permission of new file same as old file */ | |
4697 if (perm >= 0) | |
4698 (void)mch_setperm(wfname, perm); | |
4699 #endif | |
4700 #ifdef HAVE_ACL | |
4701 /* | |
4702 * Probably need to set the ACL before changing the user (can't set the | |
4703 * ACL on a file the user doesn't own). | |
4704 * On Solaris, with ZFS and the aclmode property set to "discard" (the | |
4705 * default), chmod() discards all part of a file's ACL that don't | |
4706 * represent the mode of the file. It's non-trivial for us to discover | |
4707 * whether we're in that situation, so we simply always re-set the ACL. | |
4708 */ | |
4709 # ifndef HAVE_SOLARIS_ZFS_ACL | |
4710 if (!backup_copy) | |
4711 # endif | |
4712 mch_set_acl(wfname, acl); | |
4713 #endif | |
4714 #ifdef FEAT_CRYPT | |
4715 if (buf->b_cryptstate != NULL) | |
4716 { | |
4717 crypt_free_state(buf->b_cryptstate); | |
4718 buf->b_cryptstate = NULL; | |
4719 } | |
4720 #endif | |
4721 | |
4722 #if defined(FEAT_EVAL) | |
4723 if (wfname != fname) | |
4724 { | |
4725 /* | |
4726 * The file was written to a temp file, now it needs to be | |
4727 * converted with 'charconvert' to (overwrite) the output file. | |
4728 */ | |
4729 if (end != 0) | |
4730 { | |
4731 if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, | |
4732 fenc, wfname, fname) == FAIL) | |
4733 { | |
4734 write_info.bw_conv_error = TRUE; | |
4735 end = 0; | |
4736 } | |
4737 } | |
4738 mch_remove(wfname); | |
4739 vim_free(wfname); | |
4740 } | |
4741 #endif | |
4742 } | |
4743 | |
4744 if (end == 0) | |
4745 { | |
4746 /* | |
4747 * Error encountered. | |
4748 */ | |
4749 if (errmsg == NULL) | |
4750 { | |
4751 if (write_info.bw_conv_error) | |
4752 { | |
4753 if (write_info.bw_conv_error_lnum == 0) | |
4754 errmsg = (char_u *)_("E513: write error, conversion failed (make 'fenc' empty to override)"); | |
4755 else | |
4756 { | |
4757 errmsg_allocated = TRUE; | |
4758 errmsg = alloc(300); | |
4759 vim_snprintf((char *)errmsg, 300, _("E513: write error, conversion failed in line %ld (make 'fenc' empty to override)"), | |
4760 (long)write_info.bw_conv_error_lnum); | |
4761 } | |
4762 } | |
4763 else if (got_int) | |
4764 errmsg = (char_u *)_(e_interr); | |
4765 else | |
4766 errmsg = (char_u *)_("E514: write error (file system full?)"); | |
4767 } | |
4768 | |
4769 /* | |
4770 * If we have a backup file, try to put it in place of the new file, | |
4771 * because the new file is probably corrupt. This avoids losing the | |
4772 * original file when trying to make a backup when writing the file a | |
4773 * second time. | |
4774 * When "backup_copy" is set we need to copy the backup over the new | |
4775 * file. Otherwise rename the backup file. | |
4776 * If this is OK, don't give the extra warning message. | |
4777 */ | |
4778 if (backup != NULL) | |
4779 { | |
4780 if (backup_copy) | |
4781 { | |
4782 /* This may take a while, if we were interrupted let the user | |
4783 * know we got the message. */ | |
4784 if (got_int) | |
4785 { | |
4786 msg(_(e_interr)); | |
4787 out_flush(); | |
4788 } | |
4789 if ((fd = mch_open((char *)backup, O_RDONLY | O_EXTRA, 0)) >= 0) | |
4790 { | |
4791 if ((write_info.bw_fd = mch_open((char *)fname, | |
4792 O_WRONLY | O_CREAT | O_TRUNC | O_EXTRA, | |
4793 perm & 0777)) >= 0) | |
4794 { | |
4795 /* copy the file. */ | |
4796 write_info.bw_buf = smallbuf; | |
4797 #ifdef HAS_BW_FLAGS | |
4798 write_info.bw_flags = FIO_NOCONVERT; | |
4799 #endif | |
4800 while ((write_info.bw_len = read_eintr(fd, smallbuf, | |
4801 SMBUFSIZE)) > 0) | |
4802 if (buf_write_bytes(&write_info) == FAIL) | |
4803 break; | |
4804 | |
4805 if (close(write_info.bw_fd) >= 0 | |
4806 && write_info.bw_len == 0) | |
4807 end = 1; /* success */ | |
4808 } | |
4809 close(fd); /* ignore errors for closing read file */ | |
4810 } | |
4811 } | |
4812 else | |
4813 { | |
4814 if (vim_rename(backup, fname) == 0) | |
4815 end = 1; | |
4816 } | |
4817 } | |
4818 goto fail; | |
4819 } | |
4820 | |
4821 lnum -= start; /* compute number of written lines */ | |
4822 --no_wait_return; /* may wait for return now */ | |
4823 | |
4824 #if !(defined(UNIX) || defined(VMS)) | |
4825 fname = sfname; /* use shortname now, for the messages */ | |
4826 #endif | |
4827 if (!filtering) | |
4828 { | |
4829 msg_add_fname(buf, fname); /* put fname in IObuff with quotes */ | |
4830 c = FALSE; | |
4831 if (write_info.bw_conv_error) | |
4832 { | |
4833 STRCAT(IObuff, _(" CONVERSION ERROR")); | |
4834 c = TRUE; | |
4835 if (write_info.bw_conv_error_lnum != 0) | |
4836 vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %ld;"), | |
4837 (long)write_info.bw_conv_error_lnum); | |
4838 } | |
4839 else if (notconverted) | |
4840 { | |
4841 STRCAT(IObuff, _("[NOT converted]")); | |
4842 c = TRUE; | |
4843 } | |
4844 else if (converted) | |
4845 { | |
4846 STRCAT(IObuff, _("[converted]")); | |
4847 c = TRUE; | |
4848 } | |
4849 if (device) | |
4850 { | |
4851 STRCAT(IObuff, _("[Device]")); | |
4852 c = TRUE; | |
4853 } | |
4854 else if (newfile) | |
4855 { | |
4856 STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]")); | |
4857 c = TRUE; | |
4858 } | |
4859 if (no_eol) | |
4860 { | |
4861 msg_add_eol(); | |
4862 c = TRUE; | |
4863 } | |
4864 /* may add [unix/dos/mac] */ | |
4865 if (msg_add_fileformat(fileformat)) | |
4866 c = TRUE; | |
4867 #ifdef FEAT_CRYPT | |
4868 if (wb_flags & FIO_ENCRYPTED) | |
4869 { | |
4870 crypt_append_msg(buf); | |
4871 c = TRUE; | |
4872 } | |
4873 #endif | |
4874 msg_add_lines(c, (long)lnum, nchars); /* add line/char count */ | |
4875 if (!shortmess(SHM_WRITE)) | |
4876 { | |
4877 if (append) | |
4878 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended")); | |
4879 else | |
4880 STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written")); | |
4881 } | |
4882 | |
4883 set_keep_msg((char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0), 0); | |
4884 } | |
4885 | |
4886 /* When written everything correctly: reset 'modified'. Unless not | |
4887 * writing to the original file and '+' is not in 'cpoptions'. */ | |
4888 if (reset_changed && whole && !append | |
4889 && !write_info.bw_conv_error | |
4890 && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) | |
4891 { | |
4892 unchanged(buf, TRUE, FALSE); | |
4893 /* b:changedtick is may be incremented in unchanged() but that | |
4894 * should not trigger a TextChanged event. */ | |
4895 if (buf->b_last_changedtick + 1 == CHANGEDTICK(buf)) | |
4896 buf->b_last_changedtick = CHANGEDTICK(buf); | |
4897 u_unchanged(buf); | |
4898 u_update_save_nr(buf); | |
4899 } | |
4900 | |
4901 /* | |
4902 * If written to the current file, update the timestamp of the swap file | |
4903 * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime. | |
4904 */ | |
4905 if (overwriting) | |
4906 { | |
4907 ml_timestamp(buf); | |
4908 if (append) | |
4909 buf->b_flags &= ~BF_NEW; | |
4910 else | |
4911 buf->b_flags &= ~BF_WRITE_MASK; | |
4912 } | |
4913 | |
4914 /* | |
4915 * If we kept a backup until now, and we are in patch mode, then we make | |
4916 * the backup file our 'original' file. | |
4917 */ | |
4918 if (*p_pm && dobackup) | |
4919 { | |
4920 char *org = (char *)buf_modname((buf->b_p_sn || buf->b_shortname), | |
4921 fname, p_pm, FALSE); | |
4922 | |
4923 if (backup != NULL) | |
4924 { | |
4925 stat_T st; | |
4926 | |
4927 /* | |
4928 * If the original file does not exist yet | |
4929 * the current backup file becomes the original file | |
4930 */ | |
4931 if (org == NULL) | |
4932 emsg(_("E205: Patchmode: can't save original file")); | |
4933 else if (mch_stat(org, &st) < 0) | |
4934 { | |
4935 vim_rename(backup, (char_u *)org); | |
4936 VIM_CLEAR(backup); /* don't delete the file */ | |
4937 #ifdef UNIX | |
4938 set_file_time((char_u *)org, st_old.st_atime, st_old.st_mtime); | |
4939 #endif | |
4940 } | |
4941 } | |
4942 /* | |
4943 * If there is no backup file, remember that a (new) file was | |
4944 * created. | |
4945 */ | |
4946 else | |
4947 { | |
4948 int empty_fd; | |
4949 | |
4950 if (org == NULL | |
4951 || (empty_fd = mch_open(org, | |
4952 O_CREAT | O_EXTRA | O_EXCL | O_NOFOLLOW, | |
4953 perm < 0 ? 0666 : (perm & 0777))) < 0) | |
4954 emsg(_("E206: patchmode: can't touch empty original file")); | |
4955 else | |
4956 close(empty_fd); | |
4957 } | |
4958 if (org != NULL) | |
4959 { | |
4960 mch_setperm((char_u *)org, mch_getperm(fname) & 0777); | |
4961 vim_free(org); | |
4962 } | |
4963 } | |
4964 | |
4965 // Remove the backup unless 'backup' option is set or there was a | |
4966 // conversion error. | |
4967 if (!p_bk && backup != NULL && !write_info.bw_conv_error | |
4968 && mch_remove(backup) != 0) | |
4969 emsg(_("E207: Can't delete backup file")); | |
4970 | |
4971 goto nofail; | |
4972 | |
4973 /* | |
4974 * Finish up. We get here either after failure or success. | |
4975 */ | |
4976 fail: | |
4977 --no_wait_return; /* may wait for return now */ | |
4978 nofail: | |
4979 | |
4980 /* Done saving, we accept changed buffer warnings again */ | |
4981 buf->b_saving = FALSE; | |
4982 | |
4983 vim_free(backup); | |
4984 if (buffer != smallbuf) | |
4985 vim_free(buffer); | |
4986 vim_free(fenc_tofree); | |
4987 vim_free(write_info.bw_conv_buf); | |
4988 #ifdef USE_ICONV | |
4989 if (write_info.bw_iconv_fd != (iconv_t)-1) | |
4990 { | |
4991 iconv_close(write_info.bw_iconv_fd); | |
4992 write_info.bw_iconv_fd = (iconv_t)-1; | |
4993 } | |
4994 #endif | |
4995 #ifdef HAVE_ACL | |
4996 mch_free_acl(acl); | |
4997 #endif | |
4998 | |
4999 if (errmsg != NULL) | |
5000 { | |
5001 int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0; | |
5002 | |
5003 attr = HL_ATTR(HLF_E); /* set highlight for error messages */ | |
5004 msg_add_fname(buf, | |
5005 #ifndef UNIX | |
5006 sfname | |
5007 #else | |
5008 fname | |
5009 #endif | |
5010 ); /* put file name in IObuff with quotes */ | |
5011 if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE) | |
5012 IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL; | |
5013 /* If the error message has the form "is ...", put the error number in | |
5014 * front of the file name. */ | |
5015 if (errnum != NULL) | |
5016 { | |
5017 STRMOVE(IObuff + numlen, IObuff); | |
5018 mch_memmove(IObuff, errnum, (size_t)numlen); | |
5019 } | |
5020 STRCAT(IObuff, errmsg); | |
5021 emsg((char *)IObuff); | |
5022 if (errmsg_allocated) | |
5023 vim_free(errmsg); | |
5024 | |
5025 retval = FAIL; | |
5026 if (end == 0) | |
5027 { | |
5028 msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"), | |
5029 attr | MSG_HIST); | |
5030 msg_puts_attr(_("don't quit the editor until the file is successfully written!"), | |
5031 attr | MSG_HIST); | |
5032 | |
5033 /* Update the timestamp to avoid an "overwrite changed file" | |
5034 * prompt when writing again. */ | |
5035 if (mch_stat((char *)fname, &st_old) >= 0) | |
5036 { | |
5037 buf_store_time(buf, &st_old, fname); | |
5038 buf->b_mtime_read = buf->b_mtime; | |
5039 } | |
5040 } | |
5041 } | |
5042 msg_scroll = msg_save; | |
5043 | |
5044 #ifdef FEAT_PERSISTENT_UNDO | |
5045 /* | |
5046 * When writing the whole file and 'undofile' is set, also write the undo | |
5047 * file. | |
5048 */ | |
5049 if (retval == OK && write_undo_file) | |
5050 { | |
5051 char_u hash[UNDO_HASH_SIZE]; | |
5052 | |
5053 sha256_finish(&sha_ctx, hash); | |
5054 u_write_undo(NULL, FALSE, buf, hash); | |
5055 } | |
5056 #endif | |
5057 | |
5058 #ifdef FEAT_EVAL | |
5059 if (!should_abort(retval)) | |
5060 #else | |
5061 if (!got_int) | |
5062 #endif | |
5063 { | |
5064 aco_save_T aco; | |
5065 | |
5066 curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */ | |
5067 | |
5068 /* | |
5069 * Apply POST autocommands. | |
5070 * Careful: The autocommands may call buf_write() recursively! | |
5071 */ | |
5072 aucmd_prepbuf(&aco, buf); | |
5073 | |
5074 if (append) | |
5075 apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, | |
5076 FALSE, curbuf, eap); | |
5077 else if (filtering) | |
5078 apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, | |
5079 FALSE, curbuf, eap); | |
5080 else if (reset_changed && whole) | |
5081 apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, | |
5082 FALSE, curbuf, eap); | |
5083 else | |
5084 apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, | |
5085 FALSE, curbuf, eap); | |
5086 | |
5087 /* restore curwin/curbuf and a few other things */ | |
5088 aucmd_restbuf(&aco); | |
5089 | |
5090 #ifdef FEAT_EVAL | |
5091 if (aborting()) /* autocmds may abort script processing */ | |
5092 retval = FALSE; | |
5093 #endif | |
5094 } | |
5095 | |
5096 got_int |= prev_got_int; | |
5097 | |
5098 return retval; | |
5099 } | |
5100 | |
5101 #if defined(HAVE_FSYNC) || defined(PROTO) | 2899 #if defined(HAVE_FSYNC) || defined(PROTO) |
5102 /* | 2900 /* |
5103 * Call fsync() with Mac-specific exception. | 2901 * Call fsync() with Mac-specific exception. |
5104 * Return fsync() result: zero for success. | 2902 * Return fsync() result: zero for success. |
5105 */ | 2903 */ |
5119 | 2917 |
5120 /* | 2918 /* |
5121 * Set the name of the current buffer. Use when the buffer doesn't have a | 2919 * Set the name of the current buffer. Use when the buffer doesn't have a |
5122 * name and a ":r" or ":w" command with a file name is used. | 2920 * name and a ":r" or ":w" command with a file name is used. |
5123 */ | 2921 */ |
5124 static int | 2922 int |
5125 set_rw_fname(char_u *fname, char_u *sfname) | 2923 set_rw_fname(char_u *fname, char_u *sfname) |
5126 { | 2924 { |
5127 buf_T *buf = curbuf; | 2925 buf_T *buf = curbuf; |
5128 | 2926 |
5129 /* It's like the unnamed buffer is deleted.... */ | 2927 /* It's like the unnamed buffer is deleted.... */ |
5179 | 2977 |
5180 /* | 2978 /* |
5181 * Append message for text mode to IObuff. | 2979 * Append message for text mode to IObuff. |
5182 * Return TRUE if something appended. | 2980 * Return TRUE if something appended. |
5183 */ | 2981 */ |
5184 static int | 2982 int |
5185 msg_add_fileformat(int eol_type) | 2983 msg_add_fileformat(int eol_type) |
5186 { | 2984 { |
5187 #ifndef USE_CRNL | 2985 #ifndef USE_CRNL |
5188 if (eol_type == EOL_DOS) | 2986 if (eol_type == EOL_DOS) |
5189 { | 2987 { |
5235 } | 3033 } |
5236 | 3034 |
5237 /* | 3035 /* |
5238 * Append message for missing line separator to IObuff. | 3036 * Append message for missing line separator to IObuff. |
5239 */ | 3037 */ |
5240 static void | 3038 void |
5241 msg_add_eol(void) | 3039 msg_add_eol(void) |
5242 { | 3040 { |
5243 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]")); | 3041 STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]")); |
5244 } | 3042 } |
5245 | 3043 |
5246 /* | 3044 int |
5247 * Check modification time of file, before writing to it. | |
5248 * The size isn't checked, because using a tool like "gzip" takes care of | |
5249 * using the same timestamp but can't set the size. | |
5250 */ | |
5251 static int | |
5252 check_mtime(buf_T *buf, stat_T *st) | |
5253 { | |
5254 if (buf->b_mtime_read != 0 | |
5255 && time_differs((long)st->st_mtime, buf->b_mtime_read)) | |
5256 { | |
5257 msg_scroll = TRUE; /* don't overwrite messages here */ | |
5258 msg_silent = 0; /* must give this prompt */ | |
5259 /* don't use emsg() here, don't want to flush the buffers */ | |
5260 msg_attr(_("WARNING: The file has been changed since reading it!!!"), | |
5261 HL_ATTR(HLF_E)); | |
5262 if (ask_yesno((char_u *)_("Do you really want to write to it"), | |
5263 TRUE) == 'n') | |
5264 return FAIL; | |
5265 msg_scroll = FALSE; /* always overwrite the file message now */ | |
5266 } | |
5267 return OK; | |
5268 } | |
5269 | |
5270 static int | |
5271 time_differs(long t1, long t2) | 3045 time_differs(long t1, long t2) |
5272 { | 3046 { |
5273 #if defined(__linux__) || defined(MSWIN) | 3047 #if defined(__linux__) || defined(MSWIN) |
5274 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store | 3048 /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store |
5275 * the seconds. Since the roundoff is done when flushing the inode, the | 3049 * the seconds. Since the roundoff is done when flushing the inode, the |
5279 return (t1 != t2); | 3053 return (t1 != t2); |
5280 #endif | 3054 #endif |
5281 } | 3055 } |
5282 | 3056 |
5283 /* | 3057 /* |
5284 * Call write() to write a number of bytes to the file. | |
5285 * Handles encryption and 'encoding' conversion. | |
5286 * | |
5287 * Return FAIL for failure, OK otherwise. | |
5288 */ | |
5289 static int | |
5290 buf_write_bytes(struct bw_info *ip) | |
5291 { | |
5292 int wlen; | |
5293 char_u *buf = ip->bw_buf; /* data to write */ | |
5294 int len = ip->bw_len; /* length of data */ | |
5295 #ifdef HAS_BW_FLAGS | |
5296 int flags = ip->bw_flags; /* extra flags */ | |
5297 #endif | |
5298 | |
5299 /* | |
5300 * Skip conversion when writing the crypt magic number or the BOM. | |
5301 */ | |
5302 if (!(flags & FIO_NOCONVERT)) | |
5303 { | |
5304 char_u *p; | |
5305 unsigned c; | |
5306 int n; | |
5307 | |
5308 if (flags & FIO_UTF8) | |
5309 { | |
5310 /* | |
5311 * Convert latin1 in the buffer to UTF-8 in the file. | |
5312 */ | |
5313 p = ip->bw_conv_buf; /* translate to buffer */ | |
5314 for (wlen = 0; wlen < len; ++wlen) | |
5315 p += utf_char2bytes(buf[wlen], p); | |
5316 buf = ip->bw_conv_buf; | |
5317 len = (int)(p - ip->bw_conv_buf); | |
5318 } | |
5319 else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) | |
5320 { | |
5321 /* | |
5322 * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or | |
5323 * Latin1 chars in the file. | |
5324 */ | |
5325 if (flags & FIO_LATIN1) | |
5326 p = buf; /* translate in-place (can only get shorter) */ | |
5327 else | |
5328 p = ip->bw_conv_buf; /* translate to buffer */ | |
5329 for (wlen = 0; wlen < len; wlen += n) | |
5330 { | |
5331 if (wlen == 0 && ip->bw_restlen != 0) | |
5332 { | |
5333 int l; | |
5334 | |
5335 /* Use remainder of previous call. Append the start of | |
5336 * buf[] to get a full sequence. Might still be too | |
5337 * short! */ | |
5338 l = CONV_RESTLEN - ip->bw_restlen; | |
5339 if (l > len) | |
5340 l = len; | |
5341 mch_memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); | |
5342 n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l); | |
5343 if (n > ip->bw_restlen + len) | |
5344 { | |
5345 /* We have an incomplete byte sequence at the end to | |
5346 * be written. We can't convert it without the | |
5347 * remaining bytes. Keep them for the next call. */ | |
5348 if (ip->bw_restlen + len > CONV_RESTLEN) | |
5349 return FAIL; | |
5350 ip->bw_restlen += len; | |
5351 break; | |
5352 } | |
5353 if (n > 1) | |
5354 c = utf_ptr2char(ip->bw_rest); | |
5355 else | |
5356 c = ip->bw_rest[0]; | |
5357 if (n >= ip->bw_restlen) | |
5358 { | |
5359 n -= ip->bw_restlen; | |
5360 ip->bw_restlen = 0; | |
5361 } | |
5362 else | |
5363 { | |
5364 ip->bw_restlen -= n; | |
5365 mch_memmove(ip->bw_rest, ip->bw_rest + n, | |
5366 (size_t)ip->bw_restlen); | |
5367 n = 0; | |
5368 } | |
5369 } | |
5370 else | |
5371 { | |
5372 n = utf_ptr2len_len(buf + wlen, len - wlen); | |
5373 if (n > len - wlen) | |
5374 { | |
5375 /* We have an incomplete byte sequence at the end to | |
5376 * be written. We can't convert it without the | |
5377 * remaining bytes. Keep them for the next call. */ | |
5378 if (len - wlen > CONV_RESTLEN) | |
5379 return FAIL; | |
5380 ip->bw_restlen = len - wlen; | |
5381 mch_memmove(ip->bw_rest, buf + wlen, | |
5382 (size_t)ip->bw_restlen); | |
5383 break; | |
5384 } | |
5385 if (n > 1) | |
5386 c = utf_ptr2char(buf + wlen); | |
5387 else | |
5388 c = buf[wlen]; | |
5389 } | |
5390 | |
5391 if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) | |
5392 { | |
5393 ip->bw_conv_error = TRUE; | |
5394 ip->bw_conv_error_lnum = ip->bw_start_lnum; | |
5395 } | |
5396 if (c == NL) | |
5397 ++ip->bw_start_lnum; | |
5398 } | |
5399 if (flags & FIO_LATIN1) | |
5400 len = (int)(p - buf); | |
5401 else | |
5402 { | |
5403 buf = ip->bw_conv_buf; | |
5404 len = (int)(p - ip->bw_conv_buf); | |
5405 } | |
5406 } | |
5407 | |
5408 #ifdef MSWIN | |
5409 else if (flags & FIO_CODEPAGE) | |
5410 { | |
5411 /* | |
5412 * Convert UTF-8 or codepage to UCS-2 and then to MS-Windows | |
5413 * codepage. | |
5414 */ | |
5415 char_u *from; | |
5416 size_t fromlen; | |
5417 char_u *to; | |
5418 int u8c; | |
5419 BOOL bad = FALSE; | |
5420 int needed; | |
5421 | |
5422 if (ip->bw_restlen > 0) | |
5423 { | |
5424 /* Need to concatenate the remainder of the previous call and | |
5425 * the bytes of the current call. Use the end of the | |
5426 * conversion buffer for this. */ | |
5427 fromlen = len + ip->bw_restlen; | |
5428 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; | |
5429 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen); | |
5430 mch_memmove(from + ip->bw_restlen, buf, (size_t)len); | |
5431 } | |
5432 else | |
5433 { | |
5434 from = buf; | |
5435 fromlen = len; | |
5436 } | |
5437 | |
5438 to = ip->bw_conv_buf; | |
5439 if (enc_utf8) | |
5440 { | |
5441 /* Convert from UTF-8 to UCS-2, to the start of the buffer. | |
5442 * The buffer has been allocated to be big enough. */ | |
5443 while (fromlen > 0) | |
5444 { | |
5445 n = (int)utf_ptr2len_len(from, (int)fromlen); | |
5446 if (n > (int)fromlen) /* incomplete byte sequence */ | |
5447 break; | |
5448 u8c = utf_ptr2char(from); | |
5449 *to++ = (u8c & 0xff); | |
5450 *to++ = (u8c >> 8); | |
5451 fromlen -= n; | |
5452 from += n; | |
5453 } | |
5454 | |
5455 /* Copy remainder to ip->bw_rest[] to be used for the next | |
5456 * call. */ | |
5457 if (fromlen > CONV_RESTLEN) | |
5458 { | |
5459 /* weird overlong sequence */ | |
5460 ip->bw_conv_error = TRUE; | |
5461 return FAIL; | |
5462 } | |
5463 mch_memmove(ip->bw_rest, from, fromlen); | |
5464 ip->bw_restlen = (int)fromlen; | |
5465 } | |
5466 else | |
5467 { | |
5468 /* Convert from enc_codepage to UCS-2, to the start of the | |
5469 * buffer. The buffer has been allocated to be big enough. */ | |
5470 ip->bw_restlen = 0; | |
5471 needed = MultiByteToWideChar(enc_codepage, | |
5472 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen, | |
5473 NULL, 0); | |
5474 if (needed == 0) | |
5475 { | |
5476 /* When conversion fails there may be a trailing byte. */ | |
5477 needed = MultiByteToWideChar(enc_codepage, | |
5478 MB_ERR_INVALID_CHARS, (LPCSTR)from, (int)fromlen - 1, | |
5479 NULL, 0); | |
5480 if (needed == 0) | |
5481 { | |
5482 /* Conversion doesn't work. */ | |
5483 ip->bw_conv_error = TRUE; | |
5484 return FAIL; | |
5485 } | |
5486 /* Save the trailing byte for the next call. */ | |
5487 ip->bw_rest[0] = from[fromlen - 1]; | |
5488 ip->bw_restlen = 1; | |
5489 } | |
5490 needed = MultiByteToWideChar(enc_codepage, MB_ERR_INVALID_CHARS, | |
5491 (LPCSTR)from, (int)(fromlen - ip->bw_restlen), | |
5492 (LPWSTR)to, needed); | |
5493 if (needed == 0) | |
5494 { | |
5495 /* Safety check: Conversion doesn't work. */ | |
5496 ip->bw_conv_error = TRUE; | |
5497 return FAIL; | |
5498 } | |
5499 to += needed * 2; | |
5500 } | |
5501 | |
5502 fromlen = to - ip->bw_conv_buf; | |
5503 buf = to; | |
5504 # ifdef CP_UTF8 /* VC 4.1 doesn't define CP_UTF8 */ | |
5505 if (FIO_GET_CP(flags) == CP_UTF8) | |
5506 { | |
5507 /* Convert from UCS-2 to UTF-8, using the remainder of the | |
5508 * conversion buffer. Fails when out of space. */ | |
5509 for (from = ip->bw_conv_buf; fromlen > 1; fromlen -= 2) | |
5510 { | |
5511 u8c = *from++; | |
5512 u8c += (*from++ << 8); | |
5513 to += utf_char2bytes(u8c, to); | |
5514 if (to + 6 >= ip->bw_conv_buf + ip->bw_conv_buflen) | |
5515 { | |
5516 ip->bw_conv_error = TRUE; | |
5517 return FAIL; | |
5518 } | |
5519 } | |
5520 len = (int)(to - buf); | |
5521 } | |
5522 else | |
5523 # endif | |
5524 { | |
5525 /* Convert from UCS-2 to the codepage, using the remainder of | |
5526 * the conversion buffer. If the conversion uses the default | |
5527 * character "0", the data doesn't fit in this encoding, so | |
5528 * fail. */ | |
5529 len = WideCharToMultiByte(FIO_GET_CP(flags), 0, | |
5530 (LPCWSTR)ip->bw_conv_buf, (int)fromlen / sizeof(WCHAR), | |
5531 (LPSTR)to, (int)(ip->bw_conv_buflen - fromlen), 0, | |
5532 &bad); | |
5533 if (bad) | |
5534 { | |
5535 ip->bw_conv_error = TRUE; | |
5536 return FAIL; | |
5537 } | |
5538 } | |
5539 } | |
5540 #endif | |
5541 | |
5542 #ifdef MACOS_CONVERT | |
5543 else if (flags & FIO_MACROMAN) | |
5544 { | |
5545 /* | |
5546 * Convert UTF-8 or latin1 to Apple MacRoman. | |
5547 */ | |
5548 char_u *from; | |
5549 size_t fromlen; | |
5550 | |
5551 if (ip->bw_restlen > 0) | |
5552 { | |
5553 /* Need to concatenate the remainder of the previous call and | |
5554 * the bytes of the current call. Use the end of the | |
5555 * conversion buffer for this. */ | |
5556 fromlen = len + ip->bw_restlen; | |
5557 from = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; | |
5558 mch_memmove(from, ip->bw_rest, (size_t)ip->bw_restlen); | |
5559 mch_memmove(from + ip->bw_restlen, buf, (size_t)len); | |
5560 } | |
5561 else | |
5562 { | |
5563 from = buf; | |
5564 fromlen = len; | |
5565 } | |
5566 | |
5567 if (enc2macroman(from, fromlen, | |
5568 ip->bw_conv_buf, &len, ip->bw_conv_buflen, | |
5569 ip->bw_rest, &ip->bw_restlen) == FAIL) | |
5570 { | |
5571 ip->bw_conv_error = TRUE; | |
5572 return FAIL; | |
5573 } | |
5574 buf = ip->bw_conv_buf; | |
5575 } | |
5576 #endif | |
5577 | |
5578 #ifdef USE_ICONV | |
5579 if (ip->bw_iconv_fd != (iconv_t)-1) | |
5580 { | |
5581 const char *from; | |
5582 size_t fromlen; | |
5583 char *to; | |
5584 size_t tolen; | |
5585 | |
5586 /* Convert with iconv(). */ | |
5587 if (ip->bw_restlen > 0) | |
5588 { | |
5589 char *fp; | |
5590 | |
5591 /* Need to concatenate the remainder of the previous call and | |
5592 * the bytes of the current call. Use the end of the | |
5593 * conversion buffer for this. */ | |
5594 fromlen = len + ip->bw_restlen; | |
5595 fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; | |
5596 mch_memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); | |
5597 mch_memmove(fp + ip->bw_restlen, buf, (size_t)len); | |
5598 from = fp; | |
5599 tolen = ip->bw_conv_buflen - fromlen; | |
5600 } | |
5601 else | |
5602 { | |
5603 from = (const char *)buf; | |
5604 fromlen = len; | |
5605 tolen = ip->bw_conv_buflen; | |
5606 } | |
5607 to = (char *)ip->bw_conv_buf; | |
5608 | |
5609 if (ip->bw_first) | |
5610 { | |
5611 size_t save_len = tolen; | |
5612 | |
5613 /* output the initial shift state sequence */ | |
5614 (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen); | |
5615 | |
5616 /* There is a bug in iconv() on Linux (which appears to be | |
5617 * wide-spread) which sets "to" to NULL and messes up "tolen". | |
5618 */ | |
5619 if (to == NULL) | |
5620 { | |
5621 to = (char *)ip->bw_conv_buf; | |
5622 tolen = save_len; | |
5623 } | |
5624 ip->bw_first = FALSE; | |
5625 } | |
5626 | |
5627 /* | |
5628 * If iconv() has an error or there is not enough room, fail. | |
5629 */ | |
5630 if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen) | |
5631 == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) | |
5632 || fromlen > CONV_RESTLEN) | |
5633 { | |
5634 ip->bw_conv_error = TRUE; | |
5635 return FAIL; | |
5636 } | |
5637 | |
5638 /* copy remainder to ip->bw_rest[] to be used for the next call. */ | |
5639 if (fromlen > 0) | |
5640 mch_memmove(ip->bw_rest, (void *)from, fromlen); | |
5641 ip->bw_restlen = (int)fromlen; | |
5642 | |
5643 buf = ip->bw_conv_buf; | |
5644 len = (int)((char_u *)to - ip->bw_conv_buf); | |
5645 } | |
5646 #endif | |
5647 } | |
5648 | |
5649 if (ip->bw_fd < 0) | |
5650 /* Only checking conversion, which is OK if we get here. */ | |
5651 return OK; | |
5652 | |
5653 #ifdef FEAT_CRYPT | |
5654 if (flags & FIO_ENCRYPTED) | |
5655 { | |
5656 /* Encrypt the data. Do it in-place if possible, otherwise use an | |
5657 * allocated buffer. */ | |
5658 # ifdef CRYPT_NOT_INPLACE | |
5659 if (crypt_works_inplace(ip->bw_buffer->b_cryptstate)) | |
5660 { | |
5661 # endif | |
5662 crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len); | |
5663 # ifdef CRYPT_NOT_INPLACE | |
5664 } | |
5665 else | |
5666 { | |
5667 char_u *outbuf; | |
5668 | |
5669 len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf); | |
5670 if (len == 0) | |
5671 return OK; /* Crypt layer is buffering, will flush later. */ | |
5672 wlen = write_eintr(ip->bw_fd, outbuf, len); | |
5673 vim_free(outbuf); | |
5674 return (wlen < len) ? FAIL : OK; | |
5675 } | |
5676 # endif | |
5677 } | |
5678 #endif | |
5679 | |
5680 wlen = write_eintr(ip->bw_fd, buf, len); | |
5681 return (wlen < len) ? FAIL : OK; | |
5682 } | |
5683 | |
5684 /* | |
5685 * Convert a Unicode character to bytes. | |
5686 * Return TRUE for an error, FALSE when it's OK. | |
5687 */ | |
5688 static int | |
5689 ucs2bytes( | |
5690 unsigned c, /* in: character */ | |
5691 char_u **pp, /* in/out: pointer to result */ | |
5692 int flags) /* FIO_ flags */ | |
5693 { | |
5694 char_u *p = *pp; | |
5695 int error = FALSE; | |
5696 int cc; | |
5697 | |
5698 | |
5699 if (flags & FIO_UCS4) | |
5700 { | |
5701 if (flags & FIO_ENDIAN_L) | |
5702 { | |
5703 *p++ = c; | |
5704 *p++ = (c >> 8); | |
5705 *p++ = (c >> 16); | |
5706 *p++ = (c >> 24); | |
5707 } | |
5708 else | |
5709 { | |
5710 *p++ = (c >> 24); | |
5711 *p++ = (c >> 16); | |
5712 *p++ = (c >> 8); | |
5713 *p++ = c; | |
5714 } | |
5715 } | |
5716 else if (flags & (FIO_UCS2 | FIO_UTF16)) | |
5717 { | |
5718 if (c >= 0x10000) | |
5719 { | |
5720 if (flags & FIO_UTF16) | |
5721 { | |
5722 /* Make two words, ten bits of the character in each. First | |
5723 * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */ | |
5724 c -= 0x10000; | |
5725 if (c >= 0x100000) | |
5726 error = TRUE; | |
5727 cc = ((c >> 10) & 0x3ff) + 0xd800; | |
5728 if (flags & FIO_ENDIAN_L) | |
5729 { | |
5730 *p++ = cc; | |
5731 *p++ = ((unsigned)cc >> 8); | |
5732 } | |
5733 else | |
5734 { | |
5735 *p++ = ((unsigned)cc >> 8); | |
5736 *p++ = cc; | |
5737 } | |
5738 c = (c & 0x3ff) + 0xdc00; | |
5739 } | |
5740 else | |
5741 error = TRUE; | |
5742 } | |
5743 if (flags & FIO_ENDIAN_L) | |
5744 { | |
5745 *p++ = c; | |
5746 *p++ = (c >> 8); | |
5747 } | |
5748 else | |
5749 { | |
5750 *p++ = (c >> 8); | |
5751 *p++ = c; | |
5752 } | |
5753 } | |
5754 else /* Latin1 */ | |
5755 { | |
5756 if (c >= 0x100) | |
5757 { | |
5758 error = TRUE; | |
5759 *p++ = 0xBF; | |
5760 } | |
5761 else | |
5762 *p++ = c; | |
5763 } | |
5764 | |
5765 *pp = p; | |
5766 return error; | |
5767 } | |
5768 | |
5769 /* | |
5770 * Return TRUE if file encoding "fenc" requires conversion from or to | 3058 * Return TRUE if file encoding "fenc" requires conversion from or to |
5771 * 'encoding'. | 3059 * 'encoding'. |
5772 */ | 3060 */ |
5773 static int | 3061 int |
5774 need_conversion(char_u *fenc) | 3062 need_conversion(char_u *fenc) |
5775 { | 3063 { |
5776 int same_encoding; | 3064 int same_encoding; |
5777 int enc_flags; | 3065 int enc_flags; |
5778 int fenc_flags; | 3066 int fenc_flags; |
5805 /* | 3093 /* |
5806 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the | 3094 * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the |
5807 * internal conversion. | 3095 * internal conversion. |
5808 * if "ptr" is an empty string, use 'encoding'. | 3096 * if "ptr" is an empty string, use 'encoding'. |
5809 */ | 3097 */ |
5810 static int | 3098 int |
5811 get_fio_flags(char_u *ptr) | 3099 get_fio_flags(char_u *ptr) |
5812 { | 3100 { |
5813 int prop; | 3101 int prop; |
5814 | 3102 |
5815 if (*ptr == NUL) | 3103 if (*ptr == NUL) |
5842 return FIO_LATIN1; | 3130 return FIO_LATIN1; |
5843 /* must be ENC_DBCS, requires iconv() */ | 3131 /* must be ENC_DBCS, requires iconv() */ |
5844 return 0; | 3132 return 0; |
5845 } | 3133 } |
5846 | 3134 |
5847 #ifdef MSWIN | 3135 #if defined(MSWIN) || defined(PROTO) |
5848 /* | 3136 /* |
5849 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed | 3137 * Check "ptr" for a MS-Windows codepage name and return the FIO_ flags needed |
5850 * for the conversion MS-Windows can do for us. Also accept "utf-8". | 3138 * for the conversion MS-Windows can do for us. Also accept "utf-8". |
5851 * Used for conversion between 'encoding' and 'fileencoding'. | 3139 * Used for conversion between 'encoding' and 'fileencoding'. |
5852 */ | 3140 */ |
5853 static int | 3141 int |
5854 get_win_fio_flags(char_u *ptr) | 3142 get_win_fio_flags(char_u *ptr) |
5855 { | 3143 { |
5856 int cp; | 3144 int cp; |
5857 | 3145 |
5858 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */ | 3146 /* Cannot do this when 'encoding' is not utf-8 and not a codepage. */ |
5871 } | 3159 } |
5872 return FIO_PUT_CP(cp) | FIO_CODEPAGE; | 3160 return FIO_PUT_CP(cp) | FIO_CODEPAGE; |
5873 } | 3161 } |
5874 #endif | 3162 #endif |
5875 | 3163 |
5876 #ifdef MACOS_CONVERT | 3164 #if defined(MACOS_CONVERT) || defined(PROTO) |
5877 /* | 3165 /* |
5878 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags | 3166 * Check "ptr" for a Carbon supported encoding and return the FIO_ flags |
5879 * needed for the internal conversion to/from utf-8 or latin1. | 3167 * needed for the internal conversion to/from utf-8 or latin1. |
5880 */ | 3168 */ |
5881 static int | 3169 int |
5882 get_mac_fio_flags(char_u *ptr) | 3170 get_mac_fio_flags(char_u *ptr) |
5883 { | 3171 { |
5884 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0) | 3172 if ((enc_utf8 || STRCMP(p_enc, "latin1") == 0) |
5885 && (enc_canon_props(ptr) & ENC_MACROMAN)) | 3173 && (enc_canon_props(ptr) & ENC_MACROMAN)) |
5886 return FIO_MACROMAN; | 3174 return FIO_MACROMAN; |
5940 len = 4; | 3228 len = 4; |
5941 } | 3229 } |
5942 | 3230 |
5943 *lenp = len; | 3231 *lenp = len; |
5944 return (char_u *)name; | 3232 return (char_u *)name; |
5945 } | |
5946 | |
5947 /* | |
5948 * Generate a BOM in "buf[4]" for encoding "name". | |
5949 * Return the length of the BOM (zero when no BOM). | |
5950 */ | |
5951 static int | |
5952 make_bom(char_u *buf, char_u *name) | |
5953 { | |
5954 int flags; | |
5955 char_u *p; | |
5956 | |
5957 flags = get_fio_flags(name); | |
5958 | |
5959 /* Can't put a BOM in a non-Unicode file. */ | |
5960 if (flags == FIO_LATIN1 || flags == 0) | |
5961 return 0; | |
5962 | |
5963 if (flags == FIO_UTF8) /* UTF-8 */ | |
5964 { | |
5965 buf[0] = 0xef; | |
5966 buf[1] = 0xbb; | |
5967 buf[2] = 0xbf; | |
5968 return 3; | |
5969 } | |
5970 p = buf; | |
5971 (void)ucs2bytes(0xfeff, &p, flags); | |
5972 return (int)(p - buf); | |
5973 } | 3233 } |
5974 | 3234 |
5975 /* | 3235 /* |
5976 * Try to find a shortname by comparing the fullname with the current | 3236 * Try to find a shortname by comparing the fullname with the current |
5977 * directory. | 3237 * directory. |
6515 mch_free_acl(acl); | 3775 mch_free_acl(acl); |
6516 #endif | 3776 #endif |
6517 return -1; | 3777 return -1; |
6518 } | 3778 } |
6519 | 3779 |
6520 buffer = alloc(BUFSIZE); | 3780 buffer = alloc(WRITEBUFSIZE); |
6521 if (buffer == NULL) | 3781 if (buffer == NULL) |
6522 { | 3782 { |
6523 close(fd_out); | 3783 close(fd_out); |
6524 close(fd_in); | 3784 close(fd_in); |
6525 #ifdef HAVE_ACL | 3785 #ifdef HAVE_ACL |
6526 mch_free_acl(acl); | 3786 mch_free_acl(acl); |
6527 #endif | 3787 #endif |
6528 return -1; | 3788 return -1; |
6529 } | 3789 } |
6530 | 3790 |
6531 while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0) | 3791 while ((n = read_eintr(fd_in, buffer, WRITEBUFSIZE)) > 0) |
6532 if (write_eintr(fd_out, buffer, n) != n) | 3792 if (write_eintr(fd_out, buffer, n) != n) |
6533 { | 3793 { |
6534 errmsg = _("E208: Error writing to \"%s\""); | 3794 errmsg = _("E208: Error writing to \"%s\""); |
6535 break; | 3795 break; |
6536 } | 3796 } |