Ticket #137: rough.patch
| File rough.patch, 113.8 kB (added by takkaria, 1 year ago) |
|---|
-
init.h
old new 40 40 41 41 typedef errr (*parse_info_txt_func)(char *buf, header *head); 42 42 typedef errr (*eval_info_power_func)(header *head); 43 typedef errr (*emit_info_txt_index_func)( FILE*fp, header *head, int i);44 typedef errr (*emit_info_txt_always_func)( FILE*fp, header *head);43 typedef errr (*emit_info_txt_index_func)(ang_file *fp, header *head, int i); 44 typedef errr (*emit_info_txt_always_func)(ang_file *fp, header *head); 45 45 46 46 /* 47 47 * Template file header information (see "init.c"). 16 bytes. … … 102 102 103 103 }; 104 104 105 extern errr init_info_txt( FILE*fp, char *buf, header *head,105 extern errr init_info_txt(ang_file *fp, char *buf, header *head, 106 106 parse_info_txt_func parse_info_txt_line); 107 107 108 108 extern errr eval_info(eval_info_power_func eval_info_process, header *head); 109 109 110 extern errr emit_info_txt( FILE *fp, FILE*template, char *buf, header *head,110 extern errr emit_info_txt(ang_file *fp, ang_file *template, char *buf, header *head, 111 111 emit_info_txt_index_func emit_info_txt_index, emit_info_txt_always_func emit_info_txt_always); 112 112 113 113 #ifdef ALLOW_TEMPLATES -
h-basic.h
old new 49 49 50 50 51 51 /* 52 * Everyone except RISC OS has fcntl.h 52 * Everyone except RISC OS has fcntl.h and sys/stat.h 53 53 */ 54 54 #ifndef RISCOS 55 55 # define HAVE_FCNTL_H 56 # define HAVE_STAT 56 57 #endif 57 58 58 59 #endif /* HAVE_CONFIG_H */ … … 107 108 #endif 108 109 109 110 110 /*111 * Mac support112 */113 #ifdef MACH_O_CARBON114 115 /* OS X uses filetypes when creating files. */116 # define FILE_TYPE_TEXT 'TEXT'117 # define FILE_TYPE_DATA 'DATA'118 # define FILE_TYPE_SAVE 'SAVE'119 # define FILE_TYPE(X) (_ftype = (X))120 121 #else122 123 # define FILE_TYPE(X) ((void)0)124 125 #endif126 127 128 129 111 /*** Include the library header files ***/ 130 112 131 113 /* Use various POSIX functions if available */ -
util.c
old new 2297 2297 /* Output the indent */ 2298 2298 for (i = 0; i < text_out_indent; i++) 2299 2299 { 2300 f putc(' ', text_out_file);2300 file_writec(text_out_file, ' '); 2301 2301 pos++; 2302 2302 } 2303 2303 } … … 2328 2328 else 2329 2329 { 2330 2330 /* Begin a new line */ 2331 f putc('\n', text_out_file);2331 file_writec(text_out_file, '\n'); 2332 2332 2333 2333 /* Reset */ 2334 2334 pos = 0; … … 2352 2352 ch = (isprint((unsigned char) s[n]) ? s[n] : ' '); 2353 2353 2354 2354 /* Write out the character */ 2355 f putc(ch, text_out_file);2355 file_writec(text_out_file, ch); 2356 2356 2357 2357 /* Increment */ 2358 2358 pos++; … … 2368 2368 if (*s == '\n') s++; 2369 2369 2370 2370 /* Begin a new line */ 2371 f putc('\n', text_out_file);2371 file_writec(text_out_file, '\n'); 2372 2372 2373 2373 /* Reset */ 2374 2374 pos = 0; -
Makefile.std
old new 81 81 LIBS += $(patsubst -D%,,$(patsubst -I%,, $(MODULES))) 82 82 83 83 84 # Extract system we're running on85 uname = $(shell uname -s)86 87 # Enable linux-specific modules, if requested.88 ifeq ($(uname),Linux)89 CFLAGS += -DHAVE_MKSTEMP90 endif91 92 93 84 # Object definitions 94 85 X11OBJS = maid-x11.o main-x11.o main-xaw.o main-gtk.o 95 86 MAINOBJS = main.o main-gcu.o main-sdl.o snd-sdl.o $(X11OBJS) -
z-file.c
old new 2 2 * File: z-file.c 3 3 * Purpose: Low-level file (and directory) handling 4 4 * 5 * Copyright (c) 1997-2007 Ben Harrison, pelpel, Andrew Sidwell 5 * Copyright (c) 1997-2007 Ben Harrison, pelpel, Andrew Sidwell, Matthew Jones 6 6 * 7 7 * This work is free software; you can redistribute it and/or modify it 8 8 * under the terms of either: … … 15 15 * and not for profit purposes provided that this copyright and statement 16 16 * are included in all such copies. Other copyrights may also apply. 17 17 */ 18 #include "angband.h"19 18 #include "z-file.h" 19 #include "z-virt.h" 20 #include "z-util.h" 21 #include "z-form.h" 20 22 21 23 #ifndef RISCOS 22 24 # include <sys/types.h> 23 # include <sys/stat.h>24 25 #endif 25 26 26 27 #ifdef WINDOWS 28 # include <windows.h> 27 29 # include <io.h> 28 30 #endif 29 31 32 #ifdef HAVE_FCNTL_H 33 # include <fcntl.h> 34 #endif 30 35 36 #ifdef HAVE_DIRENT_H 37 # include <sys/types.h> 38 # include <dirent.h> 39 #endif 31 40 41 #ifdef HAVE_STAT 42 # include <sys/stat.h> 43 #endif 44 32 45 /* 46 * Player info 47 */ 48 int player_uid; 49 int player_egid; 50 51 52 53 #ifdef MACH_O_CARBON 54 extern u32b _fcreator; 55 extern void fsetfileinfo(cptr path, u32b fcreator, u32b ftype); 56 #endif 57 58 59 60 /* 33 61 * Drop permissions 34 62 */ 35 63 void safe_setuid_drop(void) … … 72 100 73 101 74 102 103 75 104 /* 76 * The concept of the file routines is that all file handling should be done 77 * using as few routines as possible, since every machine is slightly 78 * different, but these routines always have the same semantics. 79 * 80 * Prhaps we should use "path_parse()" to convert from "canonical" filenames 81 * (optional leading tildes, internal wildcards, slash as the path seperator, 82 * etc) to "system" filenames (no special symbols, system-specific path 83 * seperator, etc). This would allow the program itself to assume that all 84 * filenames are "Unix" filenames, and explicitly "extract" such filenames if 85 * needed (by "path_parse()", or perhaps "path_canon()"). XXX 86 * 87 * path_temp() should probably return a "canonical" filename. XXX 88 * 89 * Note that "my_fopen()" and "my_open()" and "my_make()" and "my_kill()" 90 * and "my_move()" and "my_copy()" should all take "canonical" filenames. 91 * 92 * Canonical filenames use a leading slash to indicate an absolute path, and a 93 * leading tilde to indicate a special directory. They default to a relative 94 * path. DOS/Windows uses a leading "drivename plus colon" to indicate the 95 * use of a "special drive", and then the rest of the path is parsed normally, 96 * and MACINTOSH uses a leading colon to indicate a relative path, and an 97 * embedded colon to indicate a "drive plus absolute path", and finally 98 * defaults to a file in the current working directory, which may or may 99 * not be defined. 105 * Apply special system-specific processing before dealing with a filename. 100 106 */ 107 static errr path_parse(char *buf, size_t max, cptr file) 108 { 109 /* Accept the filename */ 110 my_strcpy(buf, file, max); 101 111 112 #ifdef RISCOS 102 113 103 #ifdef HAVE_MKSTEMP 114 /* Defined in main-ros.c */ 115 char *riscosify_name(const char *path); 116 my_strcpy(buf, riscosify_name(path), max); 104 117 105 FILE *my_fopen_temp(char *buf, size_t max) 118 #endif 119 120 /* Success */ 121 return (0); 122 } 123 124 125 126 static void path_process(char *buf, size_t len, size_t *cur_len, const char *path) 106 127 { 107 int fd; 128 #if defined(SET_UID) || defined(USE_PRIVATE_PATHS) 108 129 109 /* Prepare the buffer for mkstemp */ 110 my_strcpy(buf, "/tmp/anXXXXXX", max); 130 /* Home directory on Unixes */ 131 if (path[0] == '~') 132 { 133 const char *s; 134 const char *username = path + 1; 111 135 112 /* Secure creation of a temporary file */113 fd = mkstemp(buf);136 struct passwd *pw; 137 char user[128]; 114 138 115 /* Check the file-descriptor */ 116 if (fd < 0) return (NULL); 139 /* Look for non-user portion of the file */ 140 s = strstr(username, PATH_SEP); 141 if (s) 142 { 143 int i; 117 144 118 /* Return a file stream */ 119 return (fdopen(fd, "w")); 120 } 145 /* Keep username a decent length */ 146 if (s >= username + sizeof(user)) return; 121 147 122 #else /* HAVE_MKSTEMP */ 148 for (i = 0; username < s; ++i) user[i] = *username++; 149 user[i] = '\0'; 150 username = user; 151 } 123 152 124 /* 125 * Consider rewriting this so it uses its own buffer. 126 */ 127 FILE *my_fopen_temp(char *buf, size_t max) 128 { 129 const char *s; 153 /* Fallback -- try the "current" user */ 154 if (username[0] == '\0') 155 username = getlogin(); 130 156 131 /* Temp file */ 132 s = tmpnam(NULL); 157 /* Look up a user (or "current" user) */ 158 if (username) pw = getpwnam(username); 159 else pw = getpwuid(getuid()); 133 160 134 /* Oops */ 135 if (!s) return (NULL); 161 if (!pw) return; 136 162 137 /* Copy to buffer */ 138 my_strcpy(buf, s, max); 163 /* Copy across */ 164 strnfcat(buf, len, cur_len, "%s%s", pw->pw_dir, PATH_SEP); 165 if (s) strnfcat(buf, len, cur_len, "%s", s); 166 } 167 else 139 168 140 /* Open the file */ 141 return (my_fopen(buf, "w")); 169 #endif 170 171 { 172 strnfcat(buf, len, cur_len, "%s", path); 173 } 142 174 } 143 175 144 #endif /* HAVE_MKSTEMP */145 176 146 177 178 147 179 /* 148 * Hack -- replacement for "fgets()"180 * Create a new path string by appending a 'leaf' to 'base'. 149 181 * 150 * Read a string, without a newline, to a file 182 * On Unixes, we convert a tidle at the beginning of a basename to mean the 183 * directory, complicating things a little, but better now than later. 151 184 * 152 * Process tabs, strip internal non-printables185 * Remember to free the return value. 153 186 */ 154 #define TAB_COLUMNS 8 155 156 errr my_fgets(FILE *fff, char *buf, size_t n) 187 size_t path_build(char *buf, size_t len, const char *base, const char *leaf) 157 188 { 158 u16b i = 0; 159 char *s = buf; 160 int len; 161 162 #ifdef MACH_O_CARBON 163 164 /* For the \r vs. \r\n vs \n handling code below */ 165 bool seen_cr = FALSE; 189 size_t cur_len = 0; 190 buf[0] = '\0'; 166 191 167 #endif /* MACH_O_CARBON */ 192 if (!leaf || !leaf[0]) 193 { 194 if (base && base[0]) 195 path_process(buf, len, &cur_len, base); 168 196 169 /* Paranoia */170 if (n <= 0) return (1);197 return cur_len; 198 } 171 199 172 /* Enforce historical upper bound */173 if (n > 1024) n = 1024;174 200 175 /* Leave a byte for terminating null */ 176 len = n - 1; 177 178 /* While there's room left in the buffer */ 179 while (i < len) 201 /* 202 * If the leafname starts with the seperator, 203 * or with the tilde (on Unix), 204 * or there's no base path, 205 * We use the leafname only. 206 */ 207 #if defined(SET_UID) || defined(USE_PRIVATE_PATHS) 208 if ((!base || !base[0]) || prefix(leaf, PATH_SEP) || leaf[0] == '~') 209 #else 210 if ((!base || !base[0]) || prefix(leaf, PATH_SEP)) 211 #endif 180 212 { 181 int c; 213 path_process(buf, len, &cur_len, leaf); 214 return cur_len; 215 } 182 216 183 /*184 * Read next character - stdio buffers I/O, so there's no185 * need to buffer it again using fgets.186 */187 c = fgetc(fff);188 217 189 /* End of file */ 190 if (c == EOF) 191 { 192 /* No characters read -- signal error */ 193 if (i == 0) break; 218 /* There is both a relative leafname and a base path from which it is relative */ 219 path_process(buf, len, &cur_len, base); 220 strnfcat(buf, len, &cur_len, "%s", PATH_SEP); 221 path_process(buf, len, &cur_len, leaf); 194 222 195 /* 196 * Be nice to DOS/Windows, where a last line of a file isn't 197 * always \n terminated. 198 */ 199 *s = '\0'; 223 return cur_len; 224 } 200 225 201 /* Success */202 return (0);203 }204 226 205 #ifdef MACH_O_CARBON206 227 207 /*208 * Be nice to the Macintosh, where a file can have Mac or Unix209 * end of line, especially since the introduction of OS X.210 * MPW tools were also very tolerant to the Unix EOL.211 *212 * Watch for \r; when found, set flag and advance.213 * If the next character isn't \n, rewind the file one character214 * and act like we found \n anyway to end the line.215 */216 if (c == '\r')217 {218 seen_cr = TRUE;219 continue;220 }221 else222 seen_cr = FALSE;223 224 if (seen_cr && c != '\n')225 {226 fseek(fff, -1, SEEK_CUR);227 228 /* Put a fake newline in to end the line */229 c = '\n';230 }231 228 232 #endif /* MACH_O_CARBON*/229 /*** File-handling API ***/ 233 230 234 /* End of line*/235 if (c == '\n')236 { 237 /* Null terminate */ 238 *s = '\0'; 231 /* On Windows, fwrite() and fread() are broken. */ 232 #if defined(WINDOWS) || defined(SET_UID) 233 # define HAVE_WRITE 234 # define HAVE_READ 235 #endif 239 236 240 /* Success */241 return (0);242 }243 237 244 /* Expand a tab into spaces */ 245 if (c == '\t') 246 { 247 int tabstop; 238 /* Private structure to hold file pointers and useful info. */ 239 struct ang_file 240 { 241 FILE *fh; 242 char *fname; 243 file_mode mode; 244 bool temp; 245 }; 248 246 249 /* Next tab stop */250 tabstop = ((i + TAB_COLUMNS) / TAB_COLUMNS) * TAB_COLUMNS;251 247 252 /* Bounds check */253 if (tabstop >= len) break;254 248 255 /* Convert it to spaces */ 256 while (i < tabstop) 257 { 258 /* Store space */ 259 *s++ = ' '; 249 /** Utility functions **/ 260 250 261 /* Count */262 i++;263 }264 }265 266 /* Ignore non-printables */267 else if (isprint(c))268 {269 /* Store character in the buffer */270 *s++ = c;271 272 /* Count number of characters in the buffer */273 i++;274 }275 }276 277 /* Buffer overflow or EOF - return an empty string */278 buf[0] = '\0';279 280 /* Error */281 return (1);282 }283 284 285 251 /* 286 * Hack -- replacement for "fputs()" 287 * 288 * Dump a string, plus a newline, to a file 289 * 290 * Perhaps this function should handle internal weirdness. 252 * Delete file 'fname'. 291 253 */ 292 errr my_fputs(FILE *fff, cptr buf, size_t n) 254 bool file_delete(const char *fname) 293 255 { 294 /* Unused paramter */ 295 (void)n; 256 char buf[1024]; 296 257 297 /* Dump, ignore errors */298 (void)fprintf(fff, "%s\n", buf);258 /* Get the system-specific paths */ 259 if (path_parse(buf, sizeof(buf), fname)) return FALSE; 299 260 300 /* Success */ 301 return (0); 261 return (remove(buf) == 0); 302 262 } 303 263 304 305 264 /* 306 * Check to see if a file exists, by opening it read-only. 307 * 308 * Return TRUE if it does, FALSE if it does not. 265 * Delete file 'fname' to 'newname'. 309 266 */ 310 bool my_fexists(const char *fname)267 bool file_move(const char *fname, const char *newname) 311 268 { 312 int fd; 269 char buf[1024]; 270 char aux[1024]; 313 271 314 /* Try to open it */ 315 fd = fd_open(fname, O_RDONLY); 272 /* Get the system-specific paths */ 273 if (path_parse(buf, sizeof(buf), fname)) return (-1); 274 if (path_parse(aux, sizeof(aux), newname)) return (-1); 316 275 317 /* It worked */ 318 if (fd >= 0) 319 { 320 fd_close(fd); 321 return TRUE; 322 } 323 else 324 { 325 return FALSE; 326 } 276 return (rename(buf, aux) == 0); 327 277 } 328 278 329 279 330 331 /* The file routines for RISC OS are in main-ros.c. */332 #ifndef RISCOS333 334 335 #if defined(SET_UID) || defined(USE_PRIVATE_PATHS)336 337 280 /* 338 * Extract a "parsed" path from an initial filename 339 * Normally, we simply copy the filename into the buffer 340 * But leading tilde symbols must be handled in a special way 341 * Replace "~user/" by the home directory of the user named "user" 342 * Replace "~/" by the home directory of the current user 281 * Decide whether a file exists or not. 343 282 */ 344 errr path_parse(char *buf, size_t max, cptr file) 345 { 346 cptr u, s; 347 struct passwd *pw; 348 char user[128]; 283 bool file_exists(const char *fname); 349 284 285 #if defined(HAVE_STAT) 350 286 351 /* Assume no result */ 352 buf[0] = '\0'; 287 bool file_exists(const char *fname) 288 { 289 struct stat st; 290 return (stat(fname, &st) == 0); 291 } 353 292 354 /* No file? */ 355 if (!file) return (-1); 293 #elif defined(WINDOWS) 356 294 357 /* File needs no parsing */ 358 if (file[0] != '~') 359 { 360 my_strcpy(buf, file, max); 361 return (0); 362 } 295 bool file_exists(const char *fname) 296 { 297 char path[MAX_PATH]; 298 DWORD attrib; 363 299 364 /* Point at the user*/365 u = file+1;300 /* API says we mustn't pass anything larger than MAX_PATH */ 301 my_strcpy(path, s, sizeof(path)); 366 302 367 /* Look for non-user portion of the file */ 368 s = strstr(u, PATH_SEP); 303 attrib = GetFileAttributes(path); 304 if (attrib == INVALID_FILE_NAME) return FALSE; 305 if (attrib & FILE_ATTRIBUTE_DIRECTORY) return FALSE; 369 306 370 /* Hack -- no long user names */371 if (s && (s >= u + sizeof(user))) return (1); 307 return TRUE; 308 } 372 309 373 /* Extract a user name */ 374 if (s) 375 { 376 int i; 377 for (i = 0; u < s; ++i) user[i] = *u++; 378 user[i] = '\0'; 379 u = user; 380 } 310 #else 381 311 382 /* Look up the "current" user */ 383 if (u[0] == '\0') u = getlogin(); 312 bool file_exists(const char *fname) 313 { 314 ang_file *f = file_open(fname, MODE_READ, 0); 384 315 385 /* Look up a user (or "current" user) */ 386 if (u) pw = getpwnam(u); 387 else pw = getpwuid(getuid()); 388 389 /* Nothing found? */ 390 if (!pw) return (1); 391 392 /* Make use of the info */ 393 my_strcpy(buf, pw->pw_dir, max); 394 395 /* Append the rest of the filename, if any */ 396 if (s) my_strcat(buf, s, max); 397 398 /* Success */ 399 return (0); 316 if (f) file_close(f); 317 return (f ? TRUE : FALSE); 400 318 } 401 319 320 #endif 402 321 403 #else /* SET_UID */404 322 323 #ifndef RISCOS 324 #ifdef HAVE_STAT 405 325 406 326 /* 407 * Extract a "parsed" path from an initial filename 408 * 409 * This requires no special processing on simple machines, 410 * except for verifying the size of the filename. 327 * Return TRUE if first is newer than second, FALSE otherwise. 411 328 */ 412 errr path_parse(char *buf, size_t max, cptr file)329 bool file_newer(const char *first, const char *second) 413 330 { 414 /* Accept the filename */ 415 my_strcpy(buf, file, max); 331 struct stat first_stat, second_stat; 416 332 417 # ifdef MACH_O_CARBON 333 bool second_exists = stat(second, &second_stat) ? FALSE : TRUE; 334 bool first_exists = stat(first, &first_stat) ? FALSE : TRUE; 418 335 419 /* Fix it according to the current operating system */ 420 convert_pathname(buf); 336 /* 337 * If the first doesn't exist, the first is not newer; 338 * If the second doesn't exist, the first is always newer. 339 */ 340 if (!first_exists) return FALSE; 341 if (!second_exists) return TRUE; 421 342 422 # endif 343 if (first_stat.st_mtime >= second_stat.st_mtime) 344 return TRUE; 423 345 424 /* Success */ 425 return (0); 346 return FALSE; 426 347 } 427 348 349 #else /* HAVE_STAT */ 428 350 429 #endif /* SET_UID */ 351 bool file_newer(const char *first, const char *second) 352 { 353 /* Assume newer */ 354 return FALSE; 355 } 430 356 357 #endif /* HAVE_STAT */ 358 #endif /* RISCOS */ 431 359 432 360 433 361 362 363 /** File-handle functions **/ 364 434 365 /* 435 * Create a new path by appending a file (or directory) to a path 436 * 437 * This requires no special processing on simple machines, except 438 * for verifying the size of the filename, but note the ability to 439 * bypass the given "path" with certain special file-names. 440 * 441 * Note that the "file" may actually be a "sub-path", including 442 * a path and a file. 443 * 444 * Note that this function yields a path which must be "parsed" 445 * using the "parse" function above. 366 * Open file 'fname', in mode 'mode', with filetype 'ftype'. 367 * Returns file handle or NULL. 446 368 */ 447 errr path_build(char *buf, size_t max, cptr path, cptr file)369 ang_file *file_open(const char *fname, file_mode mode, file_type ftype) 448 370 { 449 /* Special file */ 450 if (file[0] == '~') 451 { 452 /* Use the file itself */ 453 my_strcpy(buf, file, max); 454 } 371 ang_file *f = ZNEW(ang_file); 372 char modestr[3] = "__"; 373 char buf[1024]; 455 374 456 /* Absolute file, on "normal" systems */ 457 else if (prefix(file, PATH_SEP) && !streq(PATH_SEP, "")) 458 { 459 /* Use the file itself */ 460 my_strcpy(buf, file, max); 461 } 375 /* Get the system-specific path */ 376 if (path_parse(buf, sizeof(buf), fname)) 377 return NULL; 462 378 463 /* No path given */ 464 else if (!path[0]) 379 switch (mode) 465 380 { 466 /* Use the file itself */ 467 my_strcpy(buf, file, max); 381 case MODE_WRITE: 382 modestr[0] = 'w'; 383 modestr[1] = 'b'; 384 break; 385 case MODE_READ: 386 modestr[0] = 'r'; 387 modestr[1] = 'b'; 388 break; 389 case MODE_APPEND: 390 modestr[0] = 'w'; 391 modestr[1] = 'a'; 392 break; 393 default: 394 break; 468 395 } 469 396 470 /* Path and File */ 471 else 397 f->fh = fopen(buf, modestr); 398 399 if (f->fh == NULL) 472 400 { 473 /* Build the new path */474 strnfmt(buf, max, "%s%s%s", path, PATH_SEP, file);401 FREE(f); 402 return NULL; 475 403 } 476 404 477 /* Success */ 478 return (0); 479 } 405 f->fname = string_make(buf); 406 f->mode = mode; 480 407 408 #if 0 481 409 482 /* 483 * Hack -- replacement for "fopen()" 484 */ 485 FILE *my_fopen(cptr file, cptr mode) 486 { 487 char buf[1024]; 488 FILE *fff; 410 This needs a whole bunch of work. Essentially, each port should 411 be checking the type paramater and converting it to the 412 system-specific filetype. 489 413 490 /* Hack -- Try to parse the path */ 491 if (path_parse(buf, sizeof(buf), file)) return (NULL); 414 #ifdef MACH_O_CARBON 415 /* OS X uses its own kind of filetypes */ 416 if (mode != MODE_READ) 417 fsetfileinfo(buf, _fcreator, ftype); 418 #endif 492 419 493 /* Attempt to fopen the file anyway */ 494 fff = fopen(buf, mode); 495 496 #if defined(MACH_O_CARBON) 497 498 /* Set file creator and type */ 499 if (fff && strchr(mode, 'w')) fsetfileinfo(buf, _fcreator, _ftype); 500 420 #if defined(RISCOS) && 0 421 /* do something for RISC OS here? */ 422 if (mode != MODE_READ) 423 File_SetType(n, ftype); 501 424 #endif 425 #endif 502 426 503 /* Return open file or NULL */ 504 return (fff); 427 return f; 505 428 } 506 429 507 508 430 /* 509 * Hack -- replacement for "fclose()"431 * Close file handle 'f'. 510 432 */ 511 errr my_fclose(FILE *fff)433 bool file_close(ang_file *f) 512 434 { 513 /* Require a file */514 if (!fff) return (-1);435 if (fclose(f->fh) != 0) 436 return FALSE; 515 437 516 /* Close, check for error */517 if (fclose(fff) == EOF) return (1);438 if (f->temp) 439 file_delete(f->fname); 518 440 519 /* Success */ 520 return (0); 441 FREE(f->fname); 442 FREE(f); 443 return TRUE; 521 444 } 522 445 523 446 524 447 /* 525 * Hack -- attempt to delete a file448 * Create a temporary file handle, which is deleted when closing the file. 526 449 */ 527 errr fd_kill(cptr file) 528 { 529 char buf[1024]; 450 ang_file *file_temp(void); 530 451 531 /* Hack -- Try to parse the path */ 532 if (path_parse(buf, sizeof(buf), file)) return (-1); 452 #ifdef HAVE_MKSTEMP 533 453 534 /* Remove, return 0 on success, non-zero on failure */ 535 return (remove(buf)); 536 } 537 538 539 /* 540 * Hack -- attempt to move a file 541 */ 542 errr fd_move(cptr file, cptr what) 454 ang_file *file_temp(void) 543 455 { 456 ang_file *f; 544 457 char buf[1024]; 545 char aux[1024];458 int fd; 546 459 547 /* Hack -- Try to parse the path */ 548 if (path_parse(buf, sizeof(buf), file)) return (-1); 460 my_strcpy(buf, "/tmp/anXXXXXX", sizeof(buf)); 461 fd = mkstemp(buf); 462 if (fd < 0) return NULL; 549 463 550 /* Hack -- Try to parse the path */ 551 if (path_parse(aux, sizeof(aux), what)) return (-1); 464 /* Allocate */ 465 f = ZNEW(ang_file); 466 f->fh = fdopen(fd, "a+"); 552 467 553 /* Rename, return 0 on success, non-zero on failure */ 554 return (rename(buf, aux)); 468 if (f->fh == NULL) 469 { 470 FREE(f); 471 close(fd); 472 return NULL; 473 } 474 475 f->temp = TRUE; 476 f->fname = string_make(buf); 477 f->mode = MODE_READ; /* Should really be MODE_RDWR */ 478 479 return f; 555 480 } 556 481 482 #else /* HAVE_MKSTEMP */ 557 483 558 /* 559 * Hack -- attempt to open a file descriptor (create file) 560 * 561 * This function should fail if the file already exists 562 * 563 * Note that we assume that the file should be "binary" 564 */ 565 int fd_make(cptr file, int mode) 484 ang_file *my_fopen_temp(char *buf, size_t max) 566 485 { 567 char buf[1024];568 int fd;486 ang_file *f; 487 const char *tempname; 569 488 570 /* Hack -- Try to parse the path */571 if ( path_parse(buf, sizeof(buf), file)) return (-1);489 tempname = tmpnam(NULL); 490 if (!tempname) return NULL; 572 491 573 /* Create the file, fail if exists, write-only, binary */574 f d = open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode);492 f = ZNEW(ang_file); 493 f->fh = fopen(tempname, "a+"); 575 494 576 #ifdef MACH_O_CARBON 495 if (f->fh == NULL) 496 { 497 FREE(f); 498 return NULL; 499 } 577 500 578 /* Set file creator and type */ 579 if (fd >= 0) fsetfileinfo(buf, _fcreator, _ftype); 501 f->temp = TRUE; 502 f->fname = string_make(tempname); 503 f->mode = MODE_READ; /* Should really be MODE_RDWR */ 580 504 581 #endif 582 583 /* Return descriptor */ 584 return (fd); 505 return f; 585 506 } 586 507 508 #endif /* HAVE_MKSTEMP */ 587 509 510 511 512 /** Locking functions **/ 513 588 514 /* 589 * Hack -- attempt to open a file descriptor (existing file) 590 * 591 * Note that we assume that the file should be "binary" 515 * Lock a file using POSIX locks, on platforms where this is supported. 592 516 */ 593 int fd_open(cptr file, int flags)517 void file_lock(ang_file *f) 594 518 { 595 char buf[1024]; 596 597 /* Hack -- Try to parse the path */ 598 if (path_parse(buf, sizeof(buf), file)) return (-1); 599 600 /* Attempt to open the file */ 601 return (open(buf, flags | O_BINARY, 0)); 519 #if defined(HAVE_FCNTL_H) && defined(SET_UID) 520 struct flock lock; 521 lock.l_type = (f->mode == MODE_READ ? F_RDLCK : F_WRLCK); 522 lock.l_whence = SEEK_SET; 523 lock.l_start = 0; 524 lock.l_len = 0; 525 lock.l_pid = 0; 526 fcntl(fileno(f->fh), F_SETLKW, &lock); 527 #endif /* HAVE_FCNTL_H && SET_UID */ 602 528 } 603 529 604 605 530 /* 606 * Attempt to lock a file descriptor 607 * 608 * Legal lock types -- F_UNLCK, F_RDLCK, F_WRLCK 531 * Unlock a file locked using file_lock(). 609 532 */ 610 errr fd_lock(int fd, int what)533 void file_unlock(ang_file *f) 611 534 { 612 535 #if defined(HAVE_FCNTL_H) && defined(SET_UID) 613 614 536 struct flock lock; 537 lock.l_type = F_UNLCK; 538 lock.l_whence = SEEK_SET; 539 lock.l_start = 0; 540 lock.l_len = 0; 541 lock.l_pid = 0; 542 fcntl(fileno(f->fh), F_SETLK, &lock); 543 #endif /* HAVE_FCNTL_H && SET_UID */ 544 } 615 545 616 /* Verify the fd */617 if (fd < 0) return (-1);618 546 619 lock.l_type = what; 620 lock.l_start = 0; /* Lock the entire file */ 621 lock.l_whence = SEEK_SET; /* Lock the entire file */ 622 lock.l_len = 0; /* Lock the entire file */ 547 /** Byte-based IO and functions **/ 623 548 624 /* Wait for access and set lock status */ 625 /* 626 * Change F_SETLKW to F_SETLK if it's preferable to return 627 * without locking and reporting an error instead of waiting. 628 */ 629 return (fcntl(fd, F_SETLKW, &lock)); 630 631 #else /* HAVE_FCNTL_H */ 632 633 /* Unused parameters */ 634 (void)fd; 635 (void)what; 636 637 /* Success */ 638 return (0); 639 640 #endif /* SET_UID */ 641 549 /* 550 * Seek to location 'pos' in file 'f'. 551 */ 552 bool file_seek(ang_file *f, u32b pos) 553 { 554 return (fseek(f->fh, pos, SEEK_SET) == 0); 642 555 } 643 556 644 645 557 /* 646 * Hack -- attempt to seek on a file descriptor558 * Read a single, 8-bit character from file 'f'. 647 559 */ 648 errr fd_seek(int fd, long n)560 bool file_readc(ang_file *f, byte *b) 649 561 { 650 long p;562 int i = fgetc(f->fh); 651 563 652 /* Verify fd */653 if (fd < 0) return (-1);564 if (i == EOF) 565 return FALSE; 654 566 655 /* Seek to the given position */ 656 p = lseek(fd, n, SEEK_SET); 567 *b = (byte)i; 568 return TRUE; 569 } 657 570
