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