Annotation of libwww/Library/src/HTFile.c, revision 1.69
1.1 timbl 1: /* File Access HTFile.c
2: ** ===========
3: **
4: ** This is unix-specific code in general, with some VMS bits.
1.8 timbl 5: ** These are routines for file access used by browsers.
1.1 timbl 6: **
7: ** History:
8: ** Feb 91 Written Tim Berners-Lee CERN/CN
9: ** Apr 91 vms-vms access included using DECnet syntax
10: ** 26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
11: ** Fixed access bug for relative names on VMS.
1.28 duns 12: ** Sep 93 (MD) Access to VMS files allows sharing.
13: ** 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C
1.52 duns 14: ** 22 Feb 94 (MD) Excluded two routines if we are not READING directories
1.61 frystyk 15: ** 18 May 94 (HF) Directory stuff removed and stream handling updated,
16: ** error messages introduced etc.
1.1 timbl 17: **
18: ** Bugs:
1.2 timbl 19: ** FTP: Cannot access VMS files from a unix machine.
20: ** How can we know that the
1.1 timbl 21: ** target machine runs VMS?
22: */
23:
1.65 duns 24: #ifdef VMS
25: #define GOT_READ_DIR
26: #endif /* VMS */
27:
1.28 duns 28: #ifdef VMS
29: #include "HTVMSUtils.h"
30: #endif /* VMS */
31:
1.67 frystyk 32: /* System dependent stuff */
1.61 frystyk 33: #include "tcp.h"
1.67 frystyk 34:
35: /* Library Includes */
36: #include "HTUtils.h"
1.1 timbl 37: #include "HTParse.h"
38: #include "HTTCP.h"
1.61 frystyk 39: #ifndef DECNET /* Temporary ? */
1.1 timbl 40: #include "HTFTP.h"
41: #endif
42: #include "HTAnchor.h"
1.2 timbl 43: #include "HTAtom.h"
44: #include "HTWriter.h"
45: #include "HTFWriter.h"
46: #include "HTInit.h"
1.7 secret 47: #include "HTBTree.h"
1.52 duns 48: #include "HTFormat.h"
1.54 luotonen 49: #include "HTMulti.h"
1.61 frystyk 50: #include "HTError.h"
1.67 frystyk 51: #include "HTFile.h" /* Implemented here */
52:
53: #ifdef VMS
54: PRIVATE char * suffix_separators = "._";
55: #else
56: PRIVATE char * suffix_separators = ".,_";
57: #endif /* VMS */
1.37 luotonen 58:
1.64 luotonen 59: #ifdef ISC3 /* Lauren */
60: #define _POSIX_SOURCE
61: #include <sys/limits.h>
62: #endif
63:
1.2 timbl 64: typedef struct _HTSuffix {
65: char * suffix;
1.36 luotonen 66: HTAtom * rep; /* Content-Type */
67: HTAtom * encoding; /* Content-Encoding */
68: HTAtom * language; /* Content-Language */
1.2 timbl 69: float quality;
70: } HTSuffix;
71:
72:
73: /* Controlling globals
74: **
75: */
76:
1.33 timbl 77: PUBLIC BOOL HTTakeBackup = YES;
1.47 luotonen 78: PUBLIC BOOL HTSuffixCaseSense = NO; /* Are suffixes case sensitive */
1.1 timbl 79:
80: PRIVATE char *HTMountRoot = "/Net/"; /* Where to find mounts */
1.23 duns 81: #ifdef VMS
1.28 duns 82: PRIVATE char *HTCacheRoot = "/WWW$SCRATCH"; /* Where to cache things */
1.1 timbl 83: #else
84: PRIVATE char *HTCacheRoot = "/tmp/W3_Cache_"; /* Where to cache things */
85: #endif
86:
87: /* PRIVATE char *HTSaveRoot = "$(HOME)/WWW/";*/ /* Where to save things */
88:
1.2 timbl 89:
90: /* Suffix registration
91: */
92:
93: PRIVATE HTList * HTSuffixes = 0;
1.36 luotonen 94: PRIVATE HTSuffix no_suffix = { "*", NULL, NULL, NULL, 1.0 };
95: PRIVATE HTSuffix unknown_suffix = { "*.*", NULL, NULL, NULL, 1.0};
1.2 timbl 96:
1.61 frystyk 97: /* ------------------------------------------------------------------------- */
1.11 timbl 98:
1.2 timbl 99: /* Define the representation associated with a file suffix
100: ** -------------------------------------------------------
1.11 timbl 101: **
102: ** Calling this with suffix set to "*" will set the default
103: ** representation.
104: ** Calling this with suffix set to "*.*" will set the default
105: ** representation for unknown suffix files which contain a ".".
1.25 luotonen 106: **
107: ** If filename suffix is already defined its previous
108: ** definition is overridden.
1.2 timbl 109: */
1.36 luotonen 110: PUBLIC void HTAddType ARGS4(CONST char *, suffix,
111: CONST char *, representation,
112: CONST char *, encoding,
113: float, value)
114: {
115: HTSetSuffix(suffix, representation, encoding, NULL, value);
116: }
117:
118:
119: PUBLIC void HTAddEncoding ARGS3(CONST char *, suffix,
120: CONST char *, encoding,
121: float, value)
122: {
123: HTSetSuffix(suffix, NULL, encoding, NULL, value);
124: }
125:
126:
127: PUBLIC void HTAddLanguage ARGS3(CONST char *, suffix,
128: CONST char *, language,
129: float, value)
130: {
131: HTSetSuffix(suffix, NULL, NULL, language, value);
132: }
133:
134:
135: PUBLIC void HTSetSuffix ARGS5(CONST char *, suffix,
136: CONST char *, representation,
137: CONST char *, encoding,
138: CONST char *, language,
139: float, value)
1.2 timbl 140: {
1.11 timbl 141: HTSuffix * suff;
1.25 luotonen 142:
1.19 timbl 143: if (strcmp(suffix, "*")==0) suff = &no_suffix;
144: else if (strcmp(suffix, "*.*")==0) suff = &unknown_suffix;
145: else {
1.25 luotonen 146: HTList *cur = HTSuffixes;
147:
148: while (NULL != (suff = (HTSuffix*)HTList_nextObject(cur))) {
149: if (suff->suffix && 0==strcmp(suff->suffix, suffix))
150: break;
151: }
152: if (!suff) { /* Not found -- create a new node */
153: suff = (HTSuffix*) calloc(1, sizeof(HTSuffix));
154: if (suff == NULL) outofmem(__FILE__, "HTSetSuffix");
1.36 luotonen 155:
1.25 luotonen 156: if (!HTSuffixes) HTSuffixes = HTList_new();
157: HTList_addObject(HTSuffixes, suff);
1.36 luotonen 158:
1.25 luotonen 159: StrAllocCopy(suff->suffix, suffix);
160: }
1.11 timbl 161: }
1.19 timbl 162:
1.36 luotonen 163: if (representation)
164: suff->rep = HTAtom_for(representation);
165: if (language)
166: suff->language = HTAtom_for(language);
167: if (encoding) {
1.38 luotonen 168: char * enc = NULL;
1.19 timbl 169: char * p;
170: StrAllocCopy(enc, encoding);
171: for (p=enc; *p; p++) *p = TOLOWER(*p);
1.38 luotonen 172: suff->encoding = HTAtom_for(enc);
173: free(enc); /* Leak fixed AL 6 Feb 1994 */
1.11 timbl 174: }
1.36 luotonen 175:
1.2 timbl 176: suff->quality = value;
177: }
178:
179:
1.36 luotonen 180: PRIVATE BOOL is_separator ARGS1(char, ch)
181: {
182: if (strchr(suffix_separators, ch)) return YES;
183: else return NO;
184: }
185:
186:
1.53 luotonen 187: /* PUBLIC HTSplitFilename()
1.36 luotonen 188: **
189: ** Split the filename to an array of suffixes.
190: ** Return the number of parts placed to the array.
191: ** Array should have MAX_SUFF+1 items.
192: */
1.53 luotonen 193: PUBLIC int HTSplitFilename ARGS2(char *, s_str,
1.36 luotonen 194: char **, s_arr)
195: {
196: char * start = s_str;
197: char * end;
198: char save;
199: int i;
200:
201: if (!s_str || !s_arr) return 0;
202:
203: for (i=0; i < MAX_SUFF && *start; i++) {
204: for(end=start+1; *end && !is_separator(*end); end++);
205: save = *end;
206: *end = 0;
1.38 luotonen 207: StrAllocCopy(s_arr[i], start); /* Frees the previous value */
1.36 luotonen 208: *end = save;
209: start = end;
210: }
211: FREE(s_arr[i]); /* Terminating NULL */
212: return i;
213: }
214:
215:
216:
1.53 luotonen 217: PUBLIC HTContentDescription * HTGetContentDescription ARGS2(char **, actual,
218: int, n)
1.36 luotonen 219: {
220: HTContentDescription * cd;
221: int i;
222:
223: #ifndef NO_INIT
224: if (!HTSuffixes) HTFileInit();
225: #endif
226:
1.47 luotonen 227: if (n < 2) return NULL; /* No suffix */
228:
1.36 luotonen 229: cd = (HTContentDescription*)calloc(1, sizeof(HTContentDescription));
230: if (!cd) outofmem(__FILE__, "HTContentDescription");
231:
232: cd->quality = 1.0;
233:
234: for (i=n-1; i>0; i--) {
235: HTList * cur = HTSuffixes;
236: HTSuffix * suff;
237: BOOL found = NO;
238:
1.47 luotonen 239: CTRACE(stderr, "Searching... for suffix %d: \"%s\"\n", i, actual[i]);
1.36 luotonen 240:
241: while ((suff = (HTSuffix*)HTList_nextObject(cur))) {
1.47 luotonen 242: if ((HTSuffixCaseSense && !strcmp(suff->suffix, actual[i])) ||
243: (!HTSuffixCaseSense && !strcasecomp(suff->suffix, actual[i]))){
1.36 luotonen 244:
245: if (!cd->content_type)
246: cd->content_type = suff->rep;
247: if (!cd->content_encoding)
248: cd->content_encoding = suff->encoding;
249: if (!cd->content_language)
250: cd->content_language = suff->language;
1.47 luotonen 251: if (suff->quality > 0.0000001)
252: cd->quality *= suff->quality;
1.36 luotonen 253:
254: found = YES;
255: break;
256: }
257: }
258: if (!found) {
259: if (i < n-1)
260: break;
261: else {
262: free(cd);
263: return NULL;
264: }
265: }
266: }
267: return cd;
268: }
269:
1.2 timbl 270:
1.1 timbl 271: /* Make the cache file name for a W3 document
272: ** ------------------------------------------
273: ** Make up a suitable name for saving the node in
274: **
275: ** E.g. /tmp/WWW_Cache_news/1234@cernvax.cern.ch
276: ** /tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx
277: **
278: ** On exit,
279: ** returns a malloc'ed string which must be freed by the caller.
280: */
281: PUBLIC char * HTCacheFileName ARGS1(CONST char *,name)
282: {
283: char * access = HTParse(name, "", PARSE_ACCESS);
284: char * host = HTParse(name, "", PARSE_HOST);
285: char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
286:
287: char * result;
288: result = (char *)malloc(
289: strlen(HTCacheRoot)+strlen(access)
290: +strlen(host)+strlen(path)+6+1);
291: if (result == NULL) outofmem(__FILE__, "HTCacheFileName");
292: sprintf(result, "%s/WWW/%s/%s%s", HTCacheRoot, access, host, path);
293: free(path);
294: free(access);
295: free(host);
296: return result;
297: }
298:
1.2 timbl 299:
1.1 timbl 300: /* Open a file for write, creating the path
301: ** ----------------------------------------
302: */
303: #ifdef NOT_IMPLEMENTED
304: PRIVATE int HTCreatePath ARGS1(CONST char *,path)
305: {
306: return -1;
307: }
308: #endif
309:
310: /* Convert filenames between local and WWW formats
311: ** -----------------------------------------------
312: ** Make up a suitable name for saving the node in
313: **
314: ** E.g. $(HOME)/WWW/news/1234@cernvax.cern.ch
315: ** $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx
316: **
317: ** On exit,
318: ** returns a malloc'ed string which must be freed by the caller.
1.61 frystyk 319: **
320: ** BUG: FILENAME IS NOT UNESCAPED!!!!!!
321: **
1.1 timbl 322: */
323: PUBLIC char * HTLocalName ARGS1(CONST char *,name)
324: {
325: char * access = HTParse(name, "", PARSE_ACCESS);
326: char * host = HTParse(name, "", PARSE_HOST);
327: char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
328:
1.6 timbl 329: HTUnEscape(path); /* Interpret % signs */
1.36 luotonen 330:
1.60 luotonen 331: /*
332: * CERN httpd has it's own enhanced rule system which has already
333: * done the mappings, and the local filename ("physical address")
334: * is stored in HTImServer.
335: */
1.49 luotonen 336: if (HTImServer && !*access) {
1.47 luotonen 337: free(access);
338: free(host);
1.60 luotonen 339: StrAllocCopy(path, HTImServer);
340: HTUnEscape(path);
1.65 duns 341:
342: #if VMS
343: HTVMS_checkDecnet(path);
344: #endif /* VMS */
345:
1.47 luotonen 346: CTRACE(stderr, "Local filename is \"%s\"\n", path);
347: return(path);
348: }
349:
1.27 duns 350: if (0==strcmp(access, "file")) { /* local file */
1.1 timbl 351: free(access);
1.63 frystyk 352: if ((0==strcasecomp(host, HTGetHostName())) ||
1.9 timbl 353: (0==strcasecomp(host, "localhost")) || !*host) {
1.1 timbl 354: free(host);
1.65 duns 355:
356: #if VMS
357: HTVMS_checkDecnet(path);
358: #endif /* VMS */
359:
1.61 frystyk 360: if (TRACE) fprintf(stderr, "Node........ `%s' means path `%s'\n", name, path);
1.1 timbl 361: return(path);
362: } else {
363: char * result = (char *)malloc(
364: strlen("/Net/")+strlen(host)+strlen(path)+1);
365: if (result == NULL) outofmem(__FILE__, "HTLocalName");
366: sprintf(result, "%s%s%s", "/Net/", host, path);
367: free(host);
368: free(path);
1.61 frystyk 369: if (TRACE) fprintf(stderr, "Node........ `%s' means file `%s'\n", name, result);
1.1 timbl 370: return result;
371: }
372: } else { /* other access */
373: char * result;
374: CONST char * home = (CONST char*)getenv("HOME");
1.28 duns 375: #ifdef VMS
376: if (!home)
377: home = HTCacheRoot;
378: else
379: home = HTVMS_wwwName(home);
380: #else /* not VMS */
1.1 timbl 381: if (!home) home = "/tmp";
1.28 duns 382: #endif /* not VMS */
1.1 timbl 383: result = (char *)malloc(
384: strlen(home)+strlen(access)+strlen(host)+strlen(path)+6+1);
385: if (result == NULL) outofmem(__FILE__, "HTLocalName");
386: sprintf(result, "%s/WWW/%s/%s%s", home, access, host, path);
387: free(path);
388: free(access);
389: free(host);
390: return result;
391: }
392: }
393:
394:
395: /* Make a WWW name from a full local path name
396: **
397: ** Bugs:
398: ** At present, only the names of two network root nodes are hand-coded
399: ** in and valid for the NeXT only. This should be configurable in
400: ** the general case.
401: */
402:
403: PUBLIC char * WWW_nameOfFile ARGS1 (CONST char *,name)
404: {
405: char * result;
406: #ifdef NeXT
407: if (0==strncmp("/private/Net/", name, 13)) {
408: result = (char *)malloc(7+strlen(name+13)+1);
409: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
410: sprintf(result, "file://%s", name+13);
411: } else
412: #endif
413: if (0==strncmp(HTMountRoot, name, 5)) {
414: result = (char *)malloc(7+strlen(name+5)+1);
415: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
416: sprintf(result, "file://%s", name+5);
417: } else {
1.63 frystyk 418: result = (char *)malloc(7+strlen(HTGetHostName())+strlen(name)+1);
1.1 timbl 419: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
1.63 frystyk 420: sprintf(result, "file://%s%s", HTGetHostName(), name);
1.1 timbl 421: }
422: if (TRACE) fprintf(stderr, "File `%s'\n\tmeans node `%s'\n", name, result);
423: return result;
424: }
425:
426:
1.2 timbl 427: /* Determine a suitable suffix, given the representation
428: ** -----------------------------------------------------
429: **
430: ** On entry,
431: ** rep is the atomized MIME style representation
432: **
433: ** On exit,
434: ** returns a pointer to a suitable suffix string if one has been
435: ** found, else "".
436: */
437: PUBLIC CONST char * HTFileSuffix ARGS1(HTAtom*, rep)
438: {
439: HTSuffix * suff;
1.35 luotonen 440: HTList * cur;
1.2 timbl 441:
442: #ifndef NO_INIT
443: if (!HTSuffixes) HTFileInit();
444: #endif
1.35 luotonen 445: cur = HTSuffixes;
446: while ((suff = (HTSuffix*)HTList_nextObject(cur))) {
1.2 timbl 447: if (suff->rep == rep) {
448: return suff->suffix; /* OK -- found */
449: }
450: }
451: return ""; /* Dunno */
452: }
453:
454:
1.1 timbl 455: /* Determine file format from file name
456: ** ------------------------------------
457: **
1.19 timbl 458: ** This version will return the representation and also set
459: ** a variable for the encoding.
460: **
461: ** It will handle for example x.txt, x.txt,Z, x.Z
1.2 timbl 462: */
463:
1.47 luotonen 464: PUBLIC HTFormat HTFileFormat ARGS3(CONST char *, filename,
465: HTAtom **, pencoding,
466: HTAtom **, planguage)
467: {
468: char * actual[MAX_SUFF+1];
469: int n;
470: HTContentDescription * cd;
471: HTFormat content_type = NULL;
472:
473: if (!filename) return WWW_BINARY;
474:
475: #ifndef NO_INIT
476: if (!HTSuffixes) HTFileInit();
477: #endif
478:
479: for (n=0; n<MAX_SUFF+1; n++) actual[n] = NULL;
1.53 luotonen 480: n = HTSplitFilename((char*)filename, actual);
481: cd = HTGetContentDescription(actual, n);
1.47 luotonen 482: while(n-- > 0) if (actual[n]) free(actual[n]);
483:
484: if (cd) {
485: if (pencoding) *pencoding = cd->content_encoding;
486: if (planguage) *planguage = cd->content_language;
487: content_type = cd->content_type;
488: free(cd);
489: }
490: else {
491: HTSuffix * suff = strchr(filename,'.') ?
492: (unknown_suffix.rep ? &unknown_suffix : &no_suffix) :
493: &no_suffix;
494:
495: if (pencoding) *pencoding = suff->encoding;
496: if (planguage) *planguage = suff->language;
497: content_type = suff->rep;
498: }
499:
500: if (pencoding && !*pencoding)
501: *pencoding = HTAtom_for("binary");
502: return content_type ? content_type : WWW_BINARY;
503: }
1.2 timbl 504:
505:
506: /* Determine value from file name
507: ** ------------------------------
1.1 timbl 508: **
509: */
510:
1.2 timbl 511: PUBLIC float HTFileValue ARGS1 (CONST char *,filename)
512:
1.1 timbl 513: {
1.2 timbl 514: HTSuffix * suff;
1.35 luotonen 515: HTList * cur;
1.2 timbl 516: int lf = strlen(filename);
517:
518: #ifndef NO_INIT
519: if (!HTSuffixes) HTFileInit();
520: #endif
1.35 luotonen 521: cur = HTSuffixes;
522: while ((suff = (HTSuffix*)HTList_nextObject(cur))) {
523: int ls = strlen(suff->suffix);
1.2 timbl 524: if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
1.61 frystyk 525: if (TRACE) fprintf(stderr, "File Value.. Value of %s is %.3f\n",
1.2 timbl 526: filename, suff->quality);
527: return suff->quality; /* OK -- found */
528: }
529: }
530: return 0.3; /* Dunno! */
1.1 timbl 531: }
532:
533:
534: /* Determine write access to a file
1.2 timbl 535: ** --------------------------------
536: **
537: ** On exit,
538: ** return value YES if file can be accessed and can be written to.
539: **
540: ** Bugs:
541: ** 1. No code for non-unix systems.
542: ** 2. Isn't there a quicker way?
1.1 timbl 543: */
1.61 frystyk 544: #ifndef NO_UNIX_IO
1.1 timbl 545: PUBLIC BOOL HTEditable ARGS1 (CONST char *,filename)
546: {
547: #ifdef NO_GROUPS
548: return NO; /* Safe answer till we find the correct algorithm */
549: #else
1.44 frystyk 550: #ifdef NeXT
551: int groups[NGROUPS];
552: #else
553: gid_t groups[NGROUPS];
554: #endif
1.1 timbl 555: uid_t myUid;
556: int ngroups; /* The number of groups */
557: struct stat fileStatus;
558: int i;
559:
1.65 duns 560: if (HTStat(filename, &fileStatus)) /* Get details of filename */
1.1 timbl 561: return NO; /* Can't even access file! */
562:
563: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
564: myUid = geteuid(); /* Get my user identifier */
565:
566: if (TRACE) {
567: int i;
1.19 timbl 568: fprintf(stderr,
569: "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.66 frystyk 570: (unsigned int) fileStatus.st_mode, (int) fileStatus.st_uid,
571: (int) fileStatus.st_gid, (int) myUid, ngroups);
1.68 frystyk 572: for (i=0; i<ngroups; i++) fprintf(stderr, " %d", (int) groups[i]);
1.19 timbl 573: fprintf(stderr, ")\n");
1.1 timbl 574: }
575:
576: if (fileStatus.st_mode & 0002) /* I can write anyway? */
577: return YES;
578:
579: if ((fileStatus.st_mode & 0200) /* I can write my own file? */
580: && (fileStatus.st_uid == myUid))
581: return YES;
582:
583: if (fileStatus.st_mode & 0020) /* Group I am in can write? */
584: {
585: for (i=0; i<ngroups; i++) {
586: if (groups[i] == fileStatus.st_gid)
587: return YES;
588: }
589: }
590: if (TRACE) fprintf(stderr, "\tFile is not editable.\n");
591: return NO; /* If no excuse, can't do */
592: #endif
593: }
1.61 frystyk 594: #endif /* NO_UNIX_IO */
1.1 timbl 595:
1.2 timbl 596: /* Make a save stream
597: ** ------------------
598: **
599: ** The stream must be used for writing back the file.
600: ** @@@ no backup done
601: */
1.29 timbl 602: PUBLIC HTStream * HTFileSaveStream ARGS1(HTRequest *, request)
1.2 timbl 603: {
604:
1.29 timbl 605: CONST char * addr = HTAnchor_address((HTAnchor*)request->anchor);
1.33 timbl 606: char * filename = HTLocalName(addr);
607: FILE* fp;
608:
609: /* @ Introduce CVS handling here one day
610: */
611: /* Take a backup before we do anything silly 931205
612: */
613: if (HTTakeBackup) {
1.69 ! frystyk 614: char * p;
! 615: char * backup_filename = (char *) malloc(strlen(filename)+2);
1.33 timbl 616: if (!backup_filename) outofmem(__FILE__, "taking backup");
617: strcpy(backup_filename, filename);
1.34 timbl 618: for(p=backup_filename+strlen(backup_filename);; p--) {
1.33 timbl 619: if ((*p=='/') || (p<backup_filename)) {
620: p[1]=','; /* Insert comma after slash */
621: break;
622: }
623: p[1] = p[0]; /* Move up everything to the right of it */
624: }
625:
1.65 duns 626:
627: #ifdef VMS
628: if ((fp=fopen(filename, "r", "shr=put", "shr=upd"))) { /* File exists */
629: #else /* not VMS */
1.35 luotonen 630: if ((fp=fopen(filename, "r"))) { /* File exists */
1.65 duns 631: #endif /* not VMS */
1.33 timbl 632: fclose(fp);
1.56 frystyk 633: if (TRACE) fprintf(stderr, "File `%s' exists\n", filename);
1.33 timbl 634: if (remove(backup_filename)) {
1.56 frystyk 635: if (TRACE) fprintf(stderr, "Backup file `%s' removed\n",
636: backup_filename);
1.33 timbl 637: }
638: if (rename(filename, backup_filename)) { /* != 0 => Failure */
1.56 frystyk 639: if (TRACE) fprintf(stderr, "Rename `%s' to `%s' FAILED!\n",
640: filename, backup_filename);
1.33 timbl 641: } else { /* Success */
1.56 frystyk 642: if (TRACE) fprintf(stderr, "Renamed `%s' to `%s'\n", filename,
643: backup_filename);
1.33 timbl 644: }
645: }
646: free(backup_filename);
647: } /* if take backup */
1.2 timbl 648:
1.61 frystyk 649: if ((fp = fopen(filename, "w")) == NULL) {
650: HTErrorSysAdd(request, ERR_FATAL, NO, "fopen");
651: return NULL;
652: } else
1.40 frystyk 653: return HTFWriter_new(fp, NO);
1.2 timbl 654: }
655:
1.10 secret 656:
1.1 timbl 657: /* Load a document
658: ** ---------------
659: **
660: ** On entry,
661: ** addr must point to the fully qualified hypertext reference.
662: ** This is the physsical address of the file
663: **
664: ** On exit,
1.2 timbl 665: ** returns <0 Error has occured.
666: ** HTLOADED OK
1.1 timbl 667: **
668: */
1.36 luotonen 669: PUBLIC int HTLoadFile ARGS1 (HTRequest *, request)
1.1 timbl 670: {
1.61 frystyk 671: int status = -1;
672: char *url;
1.45 luotonen 673:
1.61 frystyk 674: if (!request || !request->anchor) {
675: if (TRACE) fprintf(stderr, "HTLoadFile.. Called with bad argument\n");
1.46 luotonen 676: return HT_INTERNAL;
1.50 frystyk 677: }
1.61 frystyk 678: url = HTAnchor_physical(request->anchor);
679: if (TRACE) fprintf(stderr, "LoadFile.... Looking for `%s\'\n", url);
1.16 secret 680:
1.1 timbl 681:
682: /* For unix, we try to translate the name into the name of a transparently
683: ** mounted file.
684: **
1.61 frystyk 685: ** Not allowed in secure (HTClientHost) situations TBL 921019
1.1 timbl 686: */
687: #ifndef NO_UNIX_IO
1.17 timbl 688: /* Need protection here for telnet server but not httpd server */
1.2 timbl 689:
1.61 frystyk 690: if (!HTSecure) {
691: char * localname = HTLocalName(url); /* Does unescape! */
692: struct stat stat_info;
1.36 luotonen 693: char * multi;
1.61 frystyk 694: HTFormat format = HTFileFormat(localname, &request->content_encoding,
695: &request->content_language);
1.62 frystyk 696: if (TRACE) fprintf(stderr, "HTLoadFile.. Accessing local file system.\n");
1.36 luotonen 697:
1.1 timbl 698: #ifdef GOT_READ_DIR
1.2 timbl 699:
1.61 frystyk 700: /* Multiformat handling. If suffix matches MULTI_SUFFIX then scan
701: ** directory to find a good file.
1.2 timbl 702: **
1.61 frystyk 703: ** Bug: we don't stat the file to find the length
1.2 timbl 704: */
1.47 luotonen 705: multi = strrchr(localname, MULTI_SUFFIX[0]);
1.36 luotonen 706: if (multi && !strcmp(multi, MULTI_SUFFIX)) {
1.47 luotonen 707: char * new_path = HTMulti(request, localname, &stat_info);
708: if (new_path) {
709: FREE(localname);
710: localname = new_path;
711: HTAnchor_setPhysical(request->anchor, localname);
1.36 luotonen 712: goto open_file;
1.2 timbl 713: }
1.61 frystyk 714: else { /* If not found suitable file */
1.47 luotonen 715: FREE(localname);
1.61 frystyk 716: goto cleanup;
1.2 timbl 717: }
1.61 frystyk 718: }
719:
720: /* Check to see if the 'localname' is in fact a directory. If it is
1.1 timbl 721: ** create a new hypertext object containing a list of files and
722: ** subdirectories contained in the directory. All of these are links
723: ** to the directories or files listed.
724: */
1.65 duns 725: if (HTStat(localname, &stat_info) == -1) {
1.61 frystyk 726: if (TRACE)
727: fprintf(stderr, "HTLoadFile.. Can't stat %s\n", localname);
728: } else {
729: if (((stat_info.st_mode) & S_IFMT) == S_IFDIR) {
730: status = HTBrowseDirectory(request, localname);
731: FREE(localname);
732: goto cleanup;
733: }
734: }
1.2 timbl 735:
1.61 frystyk 736: #endif /* GOT_READ_DIR */
1.2 timbl 737:
738: open_file:
1.16 secret 739: {
1.65 duns 740: #ifdef VMS
741: FILE * fp = fopen(localname,"r","shr=put","shr=upd");
742: #else /* not VMS */
1.47 luotonen 743: FILE * fp = fopen(localname,"r");
1.65 duns 744: #endif /* not VMS */
745:
1.61 frystyk 746: if (fp) {
747: if(TRACE) fprintf (stderr, "HTLoadFile.. Opened `%s' on local file system\n", localname);
1.47 luotonen 748: if (HTEditable(localname)) {
1.16 secret 749: HTAtom * put = HTAtom_for("PUT");
1.29 timbl 750: HTList * methods = HTAnchor_methods(request->anchor);
1.16 secret 751: if (HTList_indexOf(methods, put) == (-1)) {
752: HTList_addObject(methods, put);
753: }
1.2 timbl 754: }
1.61 frystyk 755: status = HTParseFile(format, fp, request);
756: fclose(fp);
1.65 duns 757:
1.47 luotonen 758: FREE(localname);
1.61 frystyk 759: goto cleanup;
760: } else
761: HTErrorSysAdd(request, ERR_FATAL, NO, "fopen");
762: }
763: FREE(localname);
764: } /* End of local file system */
765: #endif /* NO_UNIX_IO */
1.1 timbl 766:
767: #ifndef DECNET
1.61 frystyk 768: /* Now, as transparently mounted access has failed, we try FTP. */
1.16 secret 769: {
1.61 frystyk 770: char *nodename = HTParse(url, "", PARSE_HOST);
1.63 frystyk 771: if (nodename && *nodename && strcmp(nodename, HTGetHostName())!=0) {
1.58 frystyk 772: char * newname = NULL;
1.62 frystyk 773: char *unescaped = NULL;
774: StrAllocCopy(unescaped, url);
775: HTUnEscape(unescaped);
776: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FILE_TO_FTP,
777: (void *) unescaped,
778: (int) strlen(unescaped), "HTLoadFile");
1.58 frystyk 779: StrAllocCopy(newname, "ftp:");
1.61 frystyk 780: if (!strncmp(url, "file:", 5))
781: StrAllocCat(newname, url+5);
1.58 frystyk 782: else
1.61 frystyk 783: StrAllocCat(newname, url);
1.58 frystyk 784: HTAnchor_setPhysical(request->anchor, newname);
785: free(newname);
1.61 frystyk 786: free(nodename);
1.62 frystyk 787: free(unescaped);
788: return HTLoad(request, YES); /* Jump directly to FTP module */
1.58 frystyk 789: }
1.61 frystyk 790: free(nodename);
1.1 timbl 791: }
792: #endif
793:
1.61 frystyk 794: cleanup:
1.67 frystyk 795: #if 0
1.61 frystyk 796: if (status < 0 && status != HT_INTERRUPTED) {
797: char *unescaped = NULL;
798: StrAllocCopy(unescaped, url);
799: HTUnEscape(unescaped);
800: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NOT_FOUND, (void *) unescaped,
801: (int) strlen(unescaped), "HTLoadFile");
802: free(unescaped);
1.2 timbl 803: }
1.67 frystyk 804: #endif
1.61 frystyk 805: return status;
1.1 timbl 806: }
807:
808: /* Protocol descriptors
809: */
1.29 timbl 810: GLOBALDEF PUBLIC HTProtocol HTFile = { "file", HTLoadFile,
811: HTFileSaveStream, 0 };
Webmaster