Annotation of libwww/Library/src/HTFile.c, revision 1.3
1.1 timbl 1: /* File Access HTFile.c
2: ** ===========
3: **
4: ** This is unix-specific code in general, with some VMS bits.
5: ** These are routines for file access used by WWW browsers.
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.
12: **
13: ** Bugs:
1.2 timbl 14: ** FTP: Cannot access VMS files from a unix machine.
15: ** How can we know that the
1.1 timbl 16: ** target machine runs VMS?
1.2 timbl 17: **
18: ** DIRECTORIES are NOT SORTED.. alphabetically etc.
1.1 timbl 19: */
20:
1.2 timbl 21: #include "HTFile.h" /* Implemented here */
22:
23:
1.1 timbl 24: #define INFINITY 512 /* file name length @@ FIXME */
1.2 timbl 25: #define MULTI_SUFFIX ".multi" /* Extension for scanning formats */
1.1 timbl 26:
27: #include "HTUtils.h"
28:
29: #include "WWW.h"
30: #include "HTParse.h"
31: #include "tcp.h"
32: #include "HTTCP.h"
33: #ifndef DECNET
34: #include "HTFTP.h"
35: #endif
36: #include "HTAnchor.h"
1.2 timbl 37: #include "HTAtom.h"
38: #include "HTWriter.h"
39: #include "HTFWriter.h"
40: #include "HTInit.h"
41:
42: typedef struct _HTSuffix {
43: char * suffix;
44: HTAtom * rep;
45: float quality;
46: } HTSuffix;
47:
48:
1.1 timbl 49:
50: #ifdef unix /* if this is to compile on a UNIX machine */
1.2 timbl 51: #include "HTML.h" /* For directory object building */
52:
53: #define PUTC(c) (*targetClass.put_character)(target, c)
54: #define PUTS(s) (*targetClass.put_string)(target, s)
55: #define START(e) (*targetClass.start_element)(target, e, 0, 0)
56: #define END(e) (*targetClass.end_element)(target, e)
57: #define END_TARGET (*targetClass.end_document)(target)
58: #define FREE_TARGET (*targetClass.free)(target)
59: struct _HTStructured {
60: CONST HTStructuredClass * isa;
61: /* ... */
62: };
63:
64: #endif /* unix */
65:
66:
67: /* Controlling globals
68: **
69: */
70:
71: PUBLIC int HTDirAccess = HT_DIR_OK;
72: PUBLIC int HTDirReadme = HT_DIR_README_TOP;
1.1 timbl 73:
74: PRIVATE char *HTMountRoot = "/Net/"; /* Where to find mounts */
75: #ifdef vms
76: PRIVATE char *HTCacheRoot = "/WWW$SCRATCH/"; /* Where to cache things */
77: #else
78: PRIVATE char *HTCacheRoot = "/tmp/W3_Cache_"; /* Where to cache things */
79: #endif
80:
81: /* PRIVATE char *HTSaveRoot = "$(HOME)/WWW/";*/ /* Where to save things */
82:
1.2 timbl 83:
84: /* Suffix registration
85: */
86:
87: PRIVATE HTList * HTSuffixes = 0;
88:
89: /* Define the representation associated with a file suffix
90: ** -------------------------------------------------------
91: */
92: PUBLIC void HTSetSuffix ARGS3(
93: CONST char *, suffix,
94: CONST char *, representation,
95: float, value)
96: {
97:
98: HTSuffix * suff = (HTSuffix*) calloc(1, sizeof(HTSuffix));
99: if (suff == NULL) outofmem(__FILE__, "HTSetSuffix");
100:
101: if (!HTSuffixes) HTSuffixes = HTList_new();
102:
103: StrAllocCopy(suff->suffix, suffix);
104: suff->rep = HTAtom_for(representation);
105: suff->quality = value;
106: HTList_addObject(HTSuffixes, suff);
107: }
108:
109:
110:
111:
1.1 timbl 112: #ifdef vms
113: /* Convert unix-style name into VMS name
114: ** -------------------------------------
115: **
116: ** Bug: Returns pointer to static -- non-reentrant
117: */
118: PRIVATE char * vms_name(CONST char * nn, CONST char * fn)
119: {
120:
121: /* We try converting the filename into Files-11 syntax. That is, we assume
122: ** first that the file is, like us, on a VMS node. We try remote
123: ** (or local) DECnet access. Files-11, VMS, VAX and DECnet
124: ** are trademarks of Digital Equipment Corporation.
125: ** The node is assumed to be local if the hostname WITHOUT DOMAIN
126: ** matches the local one. @@@
127: */
128: static char vmsname[INFINITY]; /* returned */
129: char * filename = (char*)malloc(strlen(fn)+1);
130: char * nodename = (char*)malloc(strlen(nn)+2+1); /* Copies to hack */
131: char *second; /* 2nd slash */
132: char *last; /* last slash */
133:
134: char * hostname = HTHostName();
135:
136: if (!filename || !nodename) outofmem(__FILE__, "vms_name");
137: strcpy(filename, fn);
138: strcpy(nodename, ""); /* On same node? Yes if node names match */
139: {
140: char *p, *q;
141: for (p=hostname, q=nn; *p && *p!='.' && *q && *q!='.'; p++, q++){
142: if (TOUPPER(*p)!=TOUPPER(*q)) {
143: strcpy(nodename, nn);
144: q = strchr(nodename, '.'); /* Mismatch */
145: if (q) *q=0; /* Chop domain */
146: strcat(nodename, "::"); /* Try decnet anyway */
147: break;
148: }
149: }
150: }
151:
152: second = strchr(filename+1, '/'); /* 2nd slash */
153: last = strrchr(filename, '/'); /* last slash */
154:
155: if (!second) { /* Only one slash */
156: sprintf(vmsname, "%s%s", nodename, filename + 1);
157: } else if(second==last) { /* Exactly two slashes */
158: *second = 0; /* Split filename from disk */
159: sprintf(vmsname, "%s%s:%s", nodename, filename+1, second+1);
160: *second = '/'; /* restore */
161: } else { /* More than two slashes */
162: char * p;
163: *second = 0; /* Split disk from directories */
164: *last = 0; /* Split dir from filename */
165: sprintf(vmsname, "%s%s:[%s]%s",
166: nodename, filename+1, second+1, last+1);
167: *second = *last = '/'; /* restore filename */
168: for (p=strchr(vmsname, '['); *p!=']'; p++)
169: if (*p=='/') *p='.'; /* Convert dir sep. to dots */
170: }
171: free(nodename);
172: free(filename);
173: return vmsname;
174: }
175:
176:
177: #endif /* vms */
178:
1.2 timbl 179:
180:
181: /* Send README file
182: **
183: ** If a README file exists, then it is inserted into the document here.
184: */
185:
1.3 ! timbl 186: #ifdef unix
1.2 timbl 187: PRIVATE void do_readme ARGS2(HTStructured *, target, CONST char *, localname)
188: {
189: FILE * fp;
190: char * readme_file_name =
191: malloc(strlen(localname)+ 1 + strlen(HT_DIR_README_FILE) + 1);
192: strcpy(readme_file_name, localname);
193: strcat(readme_file_name, "/");
194: strcat(readme_file_name, HT_DIR_README_FILE);
195:
196: fp = fopen(readme_file_name, "r");
197:
198: if (fp) {
199: HTStructuredClass targetClass;
200:
201: targetClass = *target->isa; /* (Can't init agregate in K&R) */
202: START(HTML_PRE);
203: for(;;){
204: char c = fgetc(fp);
205: if (c == (char)EOF) break;
206: switch (c) {
207: case '&':
208: case '<':
209: case '>':
210: PUTC('&');
211: PUTC('#');
212: PUTC((char)(c / 10));
213: PUTC((char) (c % 10));
214: PUTC(';');
215: break;
216: case '\n':
217: PUTC('\r'); /* Fall through */
218: default:
219: PUTC(c);
220: }
221: }
222: END(HTML_PRE);
223: fclose(fp);
224: }
225: }
1.3 ! timbl 226: #endif
1.2 timbl 227:
228:
1.1 timbl 229: /* Make the cache file name for a W3 document
230: ** ------------------------------------------
231: ** Make up a suitable name for saving the node in
232: **
233: ** E.g. /tmp/WWW_Cache_news/1234@cernvax.cern.ch
234: ** /tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx
235: **
236: ** On exit,
237: ** returns a malloc'ed string which must be freed by the caller.
238: */
239: PUBLIC char * HTCacheFileName ARGS1(CONST char *,name)
240: {
241: char * access = HTParse(name, "", PARSE_ACCESS);
242: char * host = HTParse(name, "", PARSE_HOST);
243: char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
244:
245: char * result;
246: result = (char *)malloc(
247: strlen(HTCacheRoot)+strlen(access)
248: +strlen(host)+strlen(path)+6+1);
249: if (result == NULL) outofmem(__FILE__, "HTCacheFileName");
250: sprintf(result, "%s/WWW/%s/%s%s", HTCacheRoot, access, host, path);
251: free(path);
252: free(access);
253: free(host);
254: return result;
255: }
256:
1.2 timbl 257:
1.1 timbl 258: /* Open a file for write, creating the path
259: ** ----------------------------------------
260: */
261: #ifdef NOT_IMPLEMENTED
262: PRIVATE int HTCreatePath ARGS1(CONST char *,path)
263: {
264: return -1;
265: }
266: #endif
267:
268: /* Convert filenames between local and WWW formats
269: ** -----------------------------------------------
270: ** Make up a suitable name for saving the node in
271: **
272: ** E.g. $(HOME)/WWW/news/1234@cernvax.cern.ch
273: ** $(HOME)/WWW/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 * HTLocalName 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: if (0==strcmp(access, "file")) {
285: free(access);
286: if ((0==strcmp(host, HTHostName())) || !*host) {
287: free(host);
288: if (TRACE) fprintf(stderr, "Node `%s' means path `%s'\n", name, path);
289: return(path);
290: } else {
291: char * result = (char *)malloc(
292: strlen("/Net/")+strlen(host)+strlen(path)+1);
293: if (result == NULL) outofmem(__FILE__, "HTLocalName");
294: sprintf(result, "%s%s%s", "/Net/", host, path);
295: free(host);
296: free(path);
297: if (TRACE) fprintf(stderr, "Node `%s' means file `%s'\n", name, result);
298: return result;
299: }
300: } else { /* other access */
301: char * result;
302: CONST char * home = (CONST char*)getenv("HOME");
303: if (!home) home = "/tmp";
304: result = (char *)malloc(
305: strlen(home)+strlen(access)+strlen(host)+strlen(path)+6+1);
306: if (result == NULL) outofmem(__FILE__, "HTLocalName");
307: sprintf(result, "%s/WWW/%s/%s%s", home, access, host, path);
308: free(path);
309: free(access);
310: free(host);
311: return result;
312: }
313: }
314:
315:
316: /* Make a WWW name from a full local path name
317: **
318: ** Bugs:
319: ** At present, only the names of two network root nodes are hand-coded
320: ** in and valid for the NeXT only. This should be configurable in
321: ** the general case.
322: */
323:
324: PUBLIC char * WWW_nameOfFile ARGS1 (CONST char *,name)
325: {
326: char * result;
327: #ifdef NeXT
328: if (0==strncmp("/private/Net/", name, 13)) {
329: result = (char *)malloc(7+strlen(name+13)+1);
330: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
331: sprintf(result, "file://%s", name+13);
332: } else
333: #endif
334: if (0==strncmp(HTMountRoot, name, 5)) {
335: result = (char *)malloc(7+strlen(name+5)+1);
336: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
337: sprintf(result, "file://%s", name+5);
338: } else {
339: result = (char *)malloc(7+strlen(HTHostName())+strlen(name)+1);
340: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
341: sprintf(result, "file://%s%s", HTHostName(), name);
342: }
343: if (TRACE) fprintf(stderr, "File `%s'\n\tmeans node `%s'\n", name, result);
344: return result;
345: }
346:
347:
1.2 timbl 348: /* Determine a suitable suffix, given the representation
349: ** -----------------------------------------------------
350: **
351: ** On entry,
352: ** rep is the atomized MIME style representation
353: **
354: ** On exit,
355: ** returns a pointer to a suitable suffix string if one has been
356: ** found, else "".
357: */
358: PUBLIC CONST char * HTFileSuffix ARGS1(HTAtom*, rep)
359: {
360: HTSuffix * suff;
361: int n;
362: int i;
363:
364: #ifndef NO_INIT
365: if (!HTSuffixes) HTFileInit();
366: #endif
367: n = HTList_count(HTSuffixes);
368: for(i=0; i<n; i++) {
369: suff = HTList_objectAt(HTSuffixes, i);
370: if (suff->rep == rep) {
371: return suff->suffix; /* OK -- found */
372: }
373: }
374: return ""; /* Dunno */
375: }
376:
377:
1.1 timbl 378: /* Determine file format from file name
379: ** ------------------------------------
380: **
1.2 timbl 381: */
382:
383: PUBLIC HTFormat HTFileFormat ARGS1 (CONST char *,filename)
384:
385: {
386: HTSuffix * suff;
387: int n;
388: int i;
389: int lf = strlen(filename);
390:
391: #ifndef NO_INIT
392: if (!HTSuffixes) HTFileInit();
393: #endif
394: n = HTList_count(HTSuffixes);
395: for(i=0; i<n; i++) {
396: int ls;
397: suff = HTList_objectAt(HTSuffixes, i);
398: ls = strlen(suff->suffix);
399: if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
400: return suff->rep; /* OK -- found */
401: }
402: }
403: return WWW_BINARY; /* Dunno */
404: }
405:
406:
407: /* Determine value from file name
408: ** ------------------------------
1.1 timbl 409: **
410: */
411:
1.2 timbl 412: PUBLIC float HTFileValue ARGS1 (CONST char *,filename)
413:
1.1 timbl 414: {
1.2 timbl 415: HTSuffix * suff;
416: int n;
417: int i;
418: int lf = strlen(filename);
419:
420: #ifndef NO_INIT
421: if (!HTSuffixes) HTFileInit();
422: #endif
423: n = HTList_count(HTSuffixes);
424: for(i=0; i<n; i++) {
425: int ls;
426: suff = HTList_objectAt(HTSuffixes, i);
427: ls = strlen(suff->suffix);
428: if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
429: if (TRACE) fprintf(stderr, "File: Value of %s is %.3f\n",
430: filename, suff->quality);
431: return suff->quality; /* OK -- found */
432: }
433: }
434: return 0.3; /* Dunno! */
1.1 timbl 435: }
436:
437:
438: /* Determine write access to a file
1.2 timbl 439: ** --------------------------------
440: **
441: ** On exit,
442: ** return value YES if file can be accessed and can be written to.
443: **
444: ** Bugs:
445: ** 1. No code for non-unix systems.
446: ** 2. Isn't there a quicker way?
1.1 timbl 447: */
448:
449: #ifdef vms
450: #define NO_GROUPS
451: #endif
452: #ifdef NO_UNIX_IO
453: #define NO_GROUPS
454: #endif
455: #ifdef PCNFS
456: #define NO_GROUPS
457: #endif
458:
459: PUBLIC BOOL HTEditable ARGS1 (CONST char *,filename)
460: {
461: #ifdef NO_GROUPS
462: return NO; /* Safe answer till we find the correct algorithm */
463: #else
464: int groups[NGROUPS];
465: uid_t myUid;
466: int ngroups; /* The number of groups */
467: struct stat fileStatus;
468: int i;
469:
470: if (stat(filename, &fileStatus)) /* Get details of filename */
471: return NO; /* Can't even access file! */
472:
473: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
474: myUid = geteuid(); /* Get my user identifier */
475:
476: if (TRACE) {
477: int i;
478: printf("File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
479: fileStatus.st_mode, fileStatus.st_uid, fileStatus.st_gid,
480: myUid, ngroups);
481: for (i=0; i<ngroups; i++) printf(" %d", groups[i]);
482: printf(")\n");
483: }
484:
485: if (fileStatus.st_mode & 0002) /* I can write anyway? */
486: return YES;
487:
488: if ((fileStatus.st_mode & 0200) /* I can write my own file? */
489: && (fileStatus.st_uid == myUid))
490: return YES;
491:
492: if (fileStatus.st_mode & 0020) /* Group I am in can write? */
493: {
494: for (i=0; i<ngroups; i++) {
495: if (groups[i] == fileStatus.st_gid)
496: return YES;
497: }
498: }
499: if (TRACE) fprintf(stderr, "\tFile is not editable.\n");
500: return NO; /* If no excuse, can't do */
501: #endif
502: }
503:
504:
1.2 timbl 505: /* Make a save stream
506: ** ------------------
507: **
508: ** The stream must be used for writing back the file.
509: ** @@@ no backup done
510: */
511: PUBLIC HTStream * HTFileSaveStream ARGS1(HTParentAnchor *, anchor)
512: {
513:
514: CONST char * addr = HTAnchor_address((HTAnchor*)anchor);
515: char * localname = HTLocalName(addr);
516:
517: FILE* fp = fopen(localname, "w");
518: if (!fp) return NULL;
519:
520: return HTFWriter_new(fp);
521:
522: }
523:
524:
1.1 timbl 525: /* Load a document
526: ** ---------------
527: **
528: ** On entry,
529: ** addr must point to the fully qualified hypertext reference.
530: ** This is the physsical address of the file
531: **
532: ** On exit,
1.2 timbl 533: ** returns <0 Error has occured.
534: ** HTLOADED OK
1.1 timbl 535: **
536: */
1.2 timbl 537: PUBLIC int HTLoadFile ARGS4 (
1.1 timbl 538: CONST char *, addr,
539: HTParentAnchor *, anchor,
1.2 timbl 540: HTFormat, format_out,
541: HTStream *, sink
1.1 timbl 542: )
543: {
544: char * filename;
545: HTFormat format;
546: int fd = -1; /* Unix file descriptor number = INVALID */
547: char * nodename = 0;
548: char * newname=0; /* Simplified name of file */
549:
550: /* Reduce the filename to a basic form (hopefully unique!)
551: */
552: StrAllocCopy(newname, addr);
553: filename=HTParse(newname, "", PARSE_PATH|PARSE_PUNCTUATION);
554: nodename=HTParse(newname, "", PARSE_HOST);
555: free(newname);
556:
557: format = HTFileFormat(filename);
558:
559:
560: #ifdef vms
561: /* Assume that the file is in Unix-style syntax if it contains a '/'
562: after the leading one @@ */
563: {
564: char * vmsname = strchr(filename + 1, '/') ?
565: vms_name(nodename, filename) : filename + 1;
566: fd = open(vmsname, O_RDONLY, 0);
567:
568: /* If the file wasn't VMS syntax, then perhaps it is ultrix
569: */
570: if (fd<0) {
571: char ultrixname[INFINITY];
572: if (TRACE) fprintf(stderr, "HTFile: Can't open as %s\n", vmsname);
573: sprintf(ultrixname, "%s::\"%s\"", nodename, filename);
574: fd = open(ultrixname, O_RDONLY, 0);
575: if (fd<0) {
576: if (TRACE) fprintf(stderr,
577: "HTFile: Can't open as %s\n", ultrixname);
578: }
579: }
580: }
581: #else
582:
583: /* For unix, we try to translate the name into the name of a transparently
584: ** mounted file.
585: **
586: ** Not allowed in secure (HTClienntHost) situations TBL 921019
587: */
588: #ifndef NO_UNIX_IO
1.2 timbl 589: /* @@@@ Need protection here for telnet server but not httpd server */
590:
591: /* if (!HTClientHost) */ { /* try local unix file system */
1.1 timbl 592: char * localname = HTLocalName(addr);
1.2 timbl 593: struct stat dir_info;
1.1 timbl 594:
595: #ifdef GOT_READ_DIR
1.2 timbl 596:
597: /* Multiformat handling
598: **
599: ** If needed, scan directory to find a good file.
600: ** Bug: we don't stat the file to find the length
601: */
602: if ( (strlen(localname) > strlen(MULTI_SUFFIX))
603: && (0==strcmp(localname + strlen(localname) - strlen(MULTI_SUFFIX),
604: MULTI_SUFFIX))) {
605: DIR *dp;
606: struct direct * dirbuf;
607:
608: float best = NO_VALUE_FOUND; /* So far best is bad */
609: HTFormat best_rep = NULL; /* Set when rep found */
610: struct direct best_dirbuf; /* Best dir entry so far */
611:
612: char * base = strrchr(localname, '/');
613: int baselen;
614:
615: if (!base || base == localname) goto forget_multi;
616: *base++ = 0; /* Just got directory name */
617: baselen = strlen(base)- strlen(MULTI_SUFFIX);
618: base[baselen] = 0; /* Chop off suffix */
619:
620: dp = opendir(localname);
621: if (!dp) {
622: forget_multi:
623: free(filename);
624: free(localname);
625: return HTLoadError(sink, 500,
626: "Multiformat: directory scan failed.");
627: }
628:
629: while (dirbuf = readdir(dp)) {
630: /* while there are directory entries to be read */
631: if (dirbuf->d_ino == 0) continue;
632: /* if the entry is not being used, skip it */
633:
634: if (dirbuf->d_namlen > baselen && /* Match? */
635: !strncmp(dirbuf->d_name, base, baselen)) {
636: HTFormat rep = HTFileFormat(dirbuf->d_name);
637: float value = HTStackValue(rep, format_out,
638: HTFileValue(dirbuf->d_name),
639: 0.0 /* @@@@@@ */);
640: if (value != NO_VALUE_FOUND) {
641: if (TRACE) fprintf(stderr,
642: "HTFile: value of presenting %s is %f\n",
643: HTAtom_name(rep), value);
644: if (value > best) {
645: best_rep = rep;
646: best = value;
647: best_dirbuf = *dirbuf;
648: }
649: } /* if best so far */
650: } /* if match */
651:
652: } /* end while directory entries left to read */
653: closedir(dp);
654:
655: if (best_rep) {
656: format = best_rep;
657: base[-1] = '/'; /* Restore directory name */
658: base[0] = 0;
659: StrAllocCat(localname, best_dirbuf.d_name);
660: goto open_file;
661:
662: } else { /* If not found suitable file */
663: free(filename);
664: free(localname);
665: return HTLoadError(sink, 403, /* List formats? */
666: "Could not find suitable representation for transmission.");
667: }
668: /*NOTREACHED*/
669: } /* if multi suffix */
1.1 timbl 670: /*
671: ** Check to see if the 'localname' is in fact a directory. If it is
672: ** create a new hypertext object containing a list of files and
673: ** subdirectories contained in the directory. All of these are links
674: ** to the directories or files listed.
675: ** NB This assumes the existance of a type 'struct direct', which will
676: ** hold the directory entry, and a type 'DIR' which is used to point to
677: ** the current directory being read.
678: */
679:
680:
681: if (stat(localname,&dir_info) == -1) { /* get file information */
682: /* if can't read file information */
683: if (TRACE) fprintf(stderr, "HTFile: can't stat %s\n", localname);
684:
685: } else { /* Stat was OK */
686:
687:
688: if (((dir_info.st_mode) & S_IFMT) == S_IFDIR) {
689: /* if localname is a directory */
1.2 timbl 690:
691: HTStructured* target; /* HTML object */
692: HTStructuredClass targetClass;
693:
1.1 timbl 694: DIR *dp;
695: struct direct * dirbuf;
1.2 timbl 696:
697: BOOL present[HTML_A_ATTRIBUTES];
698: char * value[HTML_A_ATTRIBUTES];
699:
1.1 timbl 700: char * tmpfilename = NULL;
701: char * shortfilename = NULL;
1.2 timbl 702: struct stat file_info;
1.1 timbl 703:
704: if (TRACE)
705: fprintf(stderr,"%s is a directory\n",localname);
706:
1.2 timbl 707: /* Check directory access.
708: ** Selective access means only those directories containing a
709: ** marker file can be browsed
710: */
711: if (HTDirAccess == HT_DIR_FORBID) {
712: return HTLoadError(sink, 403,
713: "Directory browsing is not allowed.");
714: }
715:
716:
717: if (HTDirAccess == HT_DIR_SELECTIVE) {
718: char * enable_file_name =
719: malloc(strlen(localname)+ 1 +
720: strlen(HT_DIR_ENABLE_FILE) + 1);
721: strcpy(enable_file_name, localname);
722: strcat(enable_file_name, "/");
723: strcat(enable_file_name, HT_DIR_ENABLE_FILE);
724: if (stat(enable_file_name, &file_info) != 0) {
725: free(filename);
726: free(localname);
727: return HTLoadError(sink, 403,
728: "Selective access is not enabled for this directory");
729: }
730: }
731:
732:
733: dp = opendir(localname);
734: if (!dp) {
735: free(filename);
736: free(localname);
737: return HTLoadError(sink, 403, "This directory is not readable.");
738: }
739:
740:
741: /* Directory access is allowed and possible
742: */
743: target = HTML_new(anchor, sink);
744: targetClass = *target->isa; /* Copy routine entry points */
745:
746: { int i;
747: for(i=0; i<HTML_A_ATTRIBUTES; i++)
748: present[i] = (i==HTML_A_HREF);
749: }
1.1 timbl 750:
1.2 timbl 751: START(HTML_TITLE);
752: PUTS(filename);
753: END(HTML_TITLE);
754:
755: START(HTML_H1);
1.1 timbl 756: shortfilename=strrchr(localname,'/');
757: /* put the last part of the path in shortfilename */
758: shortfilename++; /* get rid of leading '/' */
759: if (*shortfilename=='\0')
760: shortfilename--;
1.2 timbl 761: PUTS(shortfilename);
762: END(HTML_H1);
763:
764: if (HTDirReadme == HT_DIR_README_TOP)
765: do_readme(target, localname);
766:
767:
768: #ifdef SORT
1.3 ! timbl 769: HTBTree * bt = HTBTree_new(strcasecomp);
1.2 timbl 770: #endif
771: START(HTML_DIR);
772:
773: while (dirbuf = readdir(dp)) {
774: START(HTML_LI);
775: /* while there are directory entries to be read */
776: if (dirbuf->d_ino == 0)
777: /* if the entry is not being used, skip it */
778: continue;
1.1 timbl 779:
1.2 timbl 780: if (!strcmp(dirbuf->d_name,"."))
781: continue; /* skip the entry for this directory */
782:
783: if (strcmp(dirbuf->d_name,".."))
784: /* if the current entry is parent directory */
785: if ((*(dirbuf->d_name)=='.') ||
786: (*(dirbuf->d_name)==','))
787: continue; /* skip those files whose name begins
788: with '.' or ',' */
789:
790: StrAllocCopy(tmpfilename,localname);
791: if (strcmp(localname,"/"))
792: /* if filename is not root directory */
793: StrAllocCat(tmpfilename,"/");
794: else
795: if (!strcmp(dirbuf->d_name,".."))
1.1 timbl 796: continue;
1.2 timbl 797: /* if root directory and current entry is parent
798: directory, skip the current entry */
1.1 timbl 799:
1.2 timbl 800: StrAllocCat(tmpfilename,dirbuf->d_name);
801: /* append the current entry's filename to the path */
802: HTSimplify(tmpfilename);
803:
804: {
805: char * relative = (char*) malloc(
1.3 ! timbl 806: strlen(shortfilename) + strlen(dirbuf->d_name)+2);
! 807: if (relative == NULL) outofmem(__FILE__, "DirRead");
! 808: /* sprintf(relative, "%s/%s", shortfilename, dirbuf->d_name);*/
! 809: /* Won't work for root, or mapped names, so use following line */
! 810: sprintf(relative, "./%s", dirbuf->d_name);
1.2 timbl 811: value[HTML_A_HREF] = relative;
812: (*targetClass.start_element)(
813: target,HTML_A, present, value);
814: free(relative);
815: }
816: stat(tmpfilename, &file_info);
1.1 timbl 817:
1.2 timbl 818: if (strcmp(dirbuf->d_name,"..")) {
819: /* if the current entry is not the parent directory then use the file name */
820: PUTS(dirbuf->d_name);
821: if (((file_info.st_mode) & S_IFMT) == S_IFDIR)
822: PUTC('/');
823: }
824: else {
825: /* use name of parent directory */
826: char * endbit = strrchr(tmpfilename, '/');
827: PUTS("Up to ");
828: PUTS(endbit?endbit+1:tmpfilename);
829: }
830: END(HTML_A);
831:
832: } /* end while directory entries left to read */
833:
834: closedir(dp);
835: free(tmpfilename);
1.1 timbl 836:
1.2 timbl 837: #ifdef SORT
838: { /* Read out sorted filenames */
839: void * ele = NULL;
840: while ( (ele=HTBTree_next(bt, ele) != 0) {
841: if (TRACE) fprintf(stderr,
842: "Sorted: %s\n", HTBTree_object(ele);
843: /* @@@@@@@@@@@@@@@@@ */
844: }
845: HTBTree_free(bt);
846: }
847: #endif
848: END(HTML_DIR);
849:
850: if (HTDirReadme == HT_DIR_README_BOTTOM)
851: do_readme(target, localname);
852:
853: END_TARGET;
854: FREE_TARGET;
1.1 timbl 855:
856: free(filename);
857: free(localname);
1.2 timbl 858: return HT_LOADED; /* document loaded */
1.1 timbl 859:
860: } /* end if localname is directory */
861:
862: } /* end if file stat worked */
863:
864: /* End of directory reading section
865: */
866: #endif
1.2 timbl 867: open_file:
1.1 timbl 868: fd = open(localname, O_RDONLY, 0);
869: if(TRACE) printf ("HTAccess: Opening `%s' gives %d\n",
870: localname, fd);
1.2 timbl 871: if (fd>=0) { /* Good! */
872: if (HTEditable(localname)) {
873: HTAtom * put = HTAtom_for("PUT");
874: HTList * methods = HTAnchor_methods(anchor);
875: if (HTList_indexOf(methods, put) == (-1)) {
876: HTList_addObject(methods, put);
877: }
878: }
1.1 timbl 879: free(localname);
1.2 timbl 880: }
1.1 timbl 881: } /* local unix file system */
882: #endif
883: #endif
884:
885: #ifndef DECNET
886: /* Now, as transparently mounted access has failed, we try FTP.
887: */
1.2 timbl 888: if (fd<0) {
1.1 timbl 889: if (strcmp(nodename, HTHostName())!=0) {
890: free(filename);
1.2 timbl 891: fd = HTFTPLoad(addr, anchor, format_out, sink);
892: if (fd<0) return HTInetStatus("FTP file load");
893: return fd;
894: }
1.1 timbl 895: }
896: #endif
897:
898: /* All attempts have failed if fd<0.
899: */
1.2 timbl 900: if (fd<0) {
901: if (TRACE)
1.1 timbl 902: printf("Can't open `%s', errno=%d\n", filename, errno);
1.2 timbl 903: free(filename);
904: return HTLoadError(sink, 403, "Can't access requested file.");
905: }
1.1 timbl 906:
1.2 timbl 907: HTParseSocket(format, format_out, anchor, fd, sink);
908: NETCLOSE(fd);
1.1 timbl 909: free(filename);
1.2 timbl 910: return HT_LOADED;
1.1 timbl 911:
912: }
913:
914: /* Protocol descriptors
915: */
916: PUBLIC HTProtocol HTFTP = { "ftp", HTLoadFile, 0 };
1.2 timbl 917: PUBLIC HTProtocol HTFile = { "file", HTLoadFile, HTFileSaveStream };
1.1 timbl 918:
Webmaster