Annotation of libwww/Library/src/HTFile.c, revision 1.159
1.72 frystyk 1: /* HTFile.c
2: ** FILE ACCESS
3: **
1.79 frystyk 4: ** (c) COPYRIGHT MIT 1995.
1.72 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.159 ! vbancrof 6: ** @(#) $Id: HTFile.c,v 1.158 2000/08/10 16:05:39 kahan Exp $
1.1 timbl 7: **
8: ** This is unix-specific code in general, with some VMS bits.
1.8 timbl 9: ** These are routines for file access used by browsers.
1.1 timbl 10: **
11: ** History:
12: ** Feb 91 Written Tim Berners-Lee CERN/CN
13: ** Apr 91 vms-vms access included using DECnet syntax
14: ** 26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
15: ** Fixed access bug for relative names on VMS.
1.28 duns 16: ** Sep 93 (MD) Access to VMS files allows sharing.
17: ** 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C
1.52 duns 18: ** 22 Feb 94 (MD) Excluded two routines if we are not READING directories
1.61 frystyk 19: ** 18 May 94 (HF) Directory stuff removed and stream handling updated,
20: ** error messages introduced etc.
1.120 frystyk 21: ** HFN Separated transport
1.1 timbl 22: **
23: ** Bugs:
1.2 timbl 24: ** FTP: Cannot access VMS files from a unix machine.
25: ** How can we know that the
1.1 timbl 26: ** target machine runs VMS?
27: */
28:
1.67 frystyk 29: /* Library Includes */
1.143 frystyk 30: #include "wwwsys.h"
1.120 frystyk 31: #include "WWWUtil.h"
32: #include "WWWCore.h"
1.124 frystyk 33: #include "WWWDir.h"
34: #include "WWWTrans.h"
1.120 frystyk 35: #include "HTReqMan.h"
1.152 frystyk 36: #include "HTBind.h"
1.124 frystyk 37: #include "HTMulti.h"
1.67 frystyk 38: #include "HTFile.h" /* Implemented here */
39:
1.91 frystyk 40: /* Final states have negative value */
1.80 frystyk 41: typedef enum _FileState {
1.95 frystyk 42: FS_RETRY = -4,
43: FS_ERROR = -3,
44: FS_NO_DATA = -2,
45: FS_GOT_DATA = -1,
46: FS_BEGIN = 0,
1.158 kahan 47: FS_PENDING,
1.95 frystyk 48: FS_DO_CN,
49: FS_NEED_OPEN_FILE,
50: FS_NEED_BODY,
51: FS_PARSE_DIR,
52: FS_TRY_FTP
1.80 frystyk 53: } FileState;
54:
1.91 frystyk 55: /* This is the context structure for the this module */
1.77 frystyk 56: typedef struct _file_info {
1.80 frystyk 57: FileState state; /* Current state of the connection */
1.95 frystyk 58: char * local; /* Local representation of file name */
1.125 frystyk 59: struct stat stat_info; /* Contains actual file chosen */
1.134 frystyk 60: HTNet * net;
1.140 frystyk 61: HTTimer * timer;
1.77 frystyk 62: } file_info;
1.2 timbl 63:
1.80 frystyk 64: struct _HTStream {
1.112 frystyk 65: const HTStreamClass * isa;
1.80 frystyk 66: };
67:
1.120 frystyk 68: struct _HTInputStream {
69: const HTInputStreamClass * isa;
70: };
71:
1.95 frystyk 72: PRIVATE HTDirReadme dir_readme = HT_DIR_README_TOP;
73: PRIVATE HTDirAccess dir_access = HT_DIR_OK;
74: PRIVATE HTDirShow dir_show = HT_DS_SIZE+HT_DS_DATE+HT_DS_DES+HT_DS_ICON;
75: PRIVATE HTDirKey dir_key = HT_DK_CINS;
1.143 frystyk 76: PRIVATE BOOL file_suffix_binding = YES;
1.2 timbl 77:
1.61 frystyk 78: /* ------------------------------------------------------------------------- */
1.11 timbl 79:
1.95 frystyk 80: /* Directory Access
81: ** ----------------
82: */
83: PUBLIC BOOL HTFile_setDirAccess (HTDirAccess mode)
84: {
85: dir_access = mode;
86: return YES;
87: }
88:
89: PUBLIC HTDirAccess HTFile_dirAccess (void)
90: {
91: return dir_access;
92: }
93:
94: /* Directory Readme
95: ** ----------------
96: */
97: PUBLIC BOOL HTFile_setDirReadme (HTDirReadme mode)
98: {
99: dir_readme = mode;
100: return YES;
101: }
102:
103: PUBLIC HTDirReadme HTFile_dirReadme (void)
104: {
105: return dir_readme;
106: }
107:
1.143 frystyk 108: /*
109: ** Should we find the bindings between file suffixes and media types
110: ** here or not?
111: */
112: PUBLIC BOOL HTFile_doFileSuffixBinding (BOOL mode)
113: {
114: file_suffix_binding = mode;
115: return YES;
116: }
117:
118: PUBLIC BOOL HTFile_fileSuffixBinding (void)
119: {
120: return file_suffix_binding;
121: }
122:
1.95 frystyk 123: /* HTFile_readDir
124: ** --------------
125: ** Reads the directory "path"
126: ** Returns:
127: ** HT_ERROR Error
1.107 frystyk 128: ** HT_FORBIDDEN Directory reading not allowed
1.95 frystyk 129: ** HT_LOADED Successfully read the directory
1.1 timbl 130: */
1.95 frystyk 131: PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
1.1 timbl 132: {
1.112 frystyk 133: #ifdef HAVE_READDIR
134: DIR * dp;
1.95 frystyk 135: struct stat file_info;
1.124 frystyk 136: HTParentAnchor * anchor = HTRequest_anchor(request);
137: char *url = HTAnchor_physical(anchor);
1.95 frystyk 138: char fullname[HT_MAX_PATH+1];
139: char *name;
1.153 frystyk 140: HTTRACE(PROT_TRACE, "Reading..... directory\n");
1.95 frystyk 141: if (dir_access == HT_DIR_FORBID) {
1.100 frystyk 142: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 143: NULL, 0, "HTFile_readDir");
1.107 frystyk 144: return HT_FORBIDDEN;
1.95 frystyk 145: }
146:
147: /* Initialize path name for stat() */
148: if (*(name = (url+strlen(url)-1)) != '/') {
149: char *newurl = NULL;
150: StrAllocCopy(newurl, url);
151: StrAllocCat(newurl, "/");
1.110 frystyk 152: HT_FREE(file->local);
1.123 frystyk 153: file->local = HTWWWToLocal(newurl, "", HTRequest_userProfile(request));
1.110 frystyk 154: HT_FREE(newurl);
1.95 frystyk 155: }
156: strcpy(fullname, file->local);
157: name = fullname+strlen(fullname); /* Point to end of fullname */
158:
159: /* Check if access is enabled */
160: if (dir_access == HT_DIR_SELECTIVE) {
161: strcpy(name, DEFAULT_DIR_FILE);
162: if (HT_STAT(fullname, &file_info)) {
1.153 frystyk 163: HTTRACE(PROT_TRACE, "Read dir.... `%s\' not found\n" _ DEFAULT_DIR_FILE);
1.100 frystyk 164: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 165: NULL, 0, "HTFile_readDir");
1.107 frystyk 166: return HT_FORBIDDEN;
1.1 timbl 167: }
168: }
169:
1.95 frystyk 170: if ((dp = opendir(file->local))) {
1.112 frystyk 171: struct dirent * dirbuf;
1.95 frystyk 172: HTDir *dir = HTDir_new(request, dir_show, dir_key);
173: char datestr[20];
174: char sizestr[10];
175: HTFileMode mode;
176: #ifdef HT_REENTRANT
1.130 frystyk 177: struct dirent result; /* For readdir_r */
1.155 kahan 178: #endif
179:
180: #ifdef HAVE_READDIR_R_2
181: while ((dirbuf = (struct dirent *) readdir_r(dp, &result)))
182: #elif defined(HAVE_READDIR_R_3)
183: while (readdir_r(dp, &result, &dirbuf) == 0)
1.95 frystyk 184: #else
185: while ((dirbuf = readdir(dp)))
1.155 kahan 186: #endif /* HAVE_READDIR_R_2 */
1.95 frystyk 187: {
188: /* Current and parent directories are never shown in list */
1.112 frystyk 189: #ifdef HAVE_DIRENT_INO
1.95 frystyk 190: if (!dirbuf->d_ino ||
191: !strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
1.112 frystyk 192: #else
193: if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
194: #endif
1.95 frystyk 195: continue;
196:
197: /* Make a lstat on the file */
198: strcpy(name, dirbuf->d_name);
199: if (HT_LSTAT(fullname, &file_info)) {
1.153 frystyk 200: HTTRACE(PROT_TRACE, "Read dir.... lstat failed: %s\n" _ fullname);
1.95 frystyk 201: continue;
202: }
1.1 timbl 203:
1.95 frystyk 204: /* Convert stat info to fit our setup */
1.103 frystyk 205: if (((mode_t) file_info.st_mode & S_IFMT) == S_IFDIR) {
1.95 frystyk 206: #ifdef VMS
207: char *dot = strstr(name, ".DIR"); /* strip .DIR part... */
208: if (dot) *dot = '\0';
209: #endif /* VMS */
210: mode = HT_IS_DIR;
211: if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
212: } else {
213: mode = HT_IS_FILE;
214: if (dir_show & HT_DS_SIZE)
215: HTNumToStr(file_info.st_size, sizestr, 10);
216: }
217: if (dir_show & HT_DS_DATE)
218: HTDateDirStr(&file_info.st_mtime, datestr, 20);
1.1 timbl 219:
1.95 frystyk 220: /* Add to the list */
221: if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
222: break;
223: }
224: closedir(dp);
225: HTDir_free(dir);
1.127 frystyk 226: return HT_LOADED;
227: } else {
1.100 frystyk 228: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "opendir");
1.127 frystyk 229: return HT_ERROR;
230: }
1.112 frystyk 231: #else
1.114 eric 232: return HT_ERROR; /* needed for WWW_MSWINDOWS */
1.112 frystyk 233: #endif /* HAVE_READDIR */
1.1 timbl 234: }
235:
236: /* Determine write access to a file
1.2 timbl 237: ** --------------------------------
1.80 frystyk 238: ** If stat_info is NULL then the function calls stat() on it's own,
239: ** otherwise it uses the information found in stat_info
1.2 timbl 240: ** On exit,
241: ** return value YES if file can be accessed and can be written to.
242: **
243: ** Bugs:
244: ** 1. No code for non-unix systems.
245: ** 2. Isn't there a quicker way?
1.1 timbl 246: */
1.112 frystyk 247: PRIVATE BOOL HTEditable (const char * filename, struct stat * stat_info)
1.80 frystyk 248: {
1.112 frystyk 249: #ifdef GETGROUPS_T
1.80 frystyk 250: int i;
251: uid_t myUid;
252: int ngroups; /* The number of groups */
1.1 timbl 253: struct stat fileStatus;
1.80 frystyk 254: struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.112 frystyk 255: GETGROUPS_T groups[NGROUPS];
1.80 frystyk 256: if (!stat_info) {
1.90 frystyk 257: if (HT_STAT(filename, &fileStatus))
1.80 frystyk 258: return NO; /* Can't even access file! */
259: }
1.1 timbl 260: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
261: myUid = geteuid(); /* Get my user identifier */
262:
1.153 frystyk 263: #ifdef HTDEBUG
1.95 frystyk 264: if (PROT_TRACE) {
1.1 timbl 265: int i;
1.153 frystyk 266: HTTRACE(PROT_TRACE,
267: "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (" _
268: (unsigned int) fileptr->st_mode _
269: (int) fileptr->st_uid _ (int) fileptr->st_gid _
270: (int) myUid _ ngroups);
271: for (i=0; i<ngroups; i++) HTTRACE(PROT_TRACE, " %d" _ (int) groups[i]);
272: HTTRACE(PROT_TRACE, ")\n");
1.1 timbl 273: }
1.153 frystyk 274: #endif /* HTDEBUG */
1.1 timbl 275:
1.80 frystyk 276: if (fileptr->st_mode & 0002) /* I can write anyway? */
1.1 timbl 277: return YES;
278:
1.80 frystyk 279: if ((fileptr->st_mode & 0200) /* I can write my own file? */
280: && (fileptr->st_uid == myUid))
1.1 timbl 281: return YES;
282:
1.80 frystyk 283: if (fileptr->st_mode & 0020) /* Group I am in can write? */
1.1 timbl 284: {
285: for (i=0; i<ngroups; i++) {
1.80 frystyk 286: if (groups[i] == fileptr->st_gid)
1.1 timbl 287: return YES;
288: }
289: }
1.153 frystyk 290: HTTRACE(PROT_TRACE, "\tFile is not editable.\n");
1.1 timbl 291: return NO; /* If no excuse, can't do */
1.80 frystyk 292: #else
293: /*
294: ** We don't know and can't find out. Can we be sure that when opening
295: ** a file in mode "a" that the file is not modified?
296: */
297: return NO;
1.112 frystyk 298: #endif /* GETGROUPS_T */
1.1 timbl 299: }
1.80 frystyk 300:
1.91 frystyk 301: /* FileCleanup
302: ** -----------
1.80 frystyk 303: ** This function closes the connection and frees memory.
1.91 frystyk 304: ** Returns YES on OK, else NO
1.80 frystyk 305: */
1.91 frystyk 306: PRIVATE int FileCleanup (HTRequest *req, int status)
1.80 frystyk 307: {
1.126 frystyk 308: HTNet * net = HTRequest_net(req);
309: file_info * file = (file_info *) HTNet_context(net);
310: HTStream * input = HTRequest_inputStream(req);
1.106 frystyk 311:
312: /* Free stream with data TO Local file system */
1.149 frystyk 313: if (input) {
314: if (status == HT_INTERRUPTED)
315: (*input->isa->abort)(input, NULL);
316: else
317: (*input->isa->_free)(input);
318: HTRequest_setInputStream(req, NULL);
1.106 frystyk 319: }
320:
1.140 frystyk 321: /*
1.149 frystyk 322: ** Remove if we have registered a timer function as a callback
1.140 frystyk 323: */
324: if (file->timer) {
325: HTTimer_delete(file->timer);
326: file->timer = NULL;
327: }
328:
1.91 frystyk 329: if (file) {
1.110 frystyk 330: HT_FREE(file->local);
331: HT_FREE(file);
1.80 frystyk 332: }
1.128 frystyk 333: HTNet_delete(net, status);
1.91 frystyk 334: return YES;
1.80 frystyk 335: }
336:
337:
1.1 timbl 338: /* Load a document
339: ** ---------------
340: **
341: ** On entry,
1.80 frystyk 342: ** request This is the request structure
1.1 timbl 343: ** On exit,
1.91 frystyk 344: ** returns HT_ERROR Error has occured in call back
345: ** HT_OK Call back was OK
1.1 timbl 346: */
1.134 frystyk 347: PRIVATE int FileEvent (SOCKET soc, void * pVoid, HTEventType type);
348:
349: PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request)
1.1 timbl 350: {
1.134 frystyk 351: file_info *file; /* Specific access information */
352: HTNet * net = HTRequest_net(request);
353: HTParentAnchor * anchor = HTRequest_anchor(request);
354:
1.153 frystyk 355: HTTRACE(PROT_TRACE, "HTLoadFile.. Looking for `%s\'\n" _
1.134 frystyk 356: HTAnchor_physical(anchor));
357: if ((file = (file_info *) HT_CALLOC(1, sizeof(file_info))) == NULL)
358: HT_OUTOFMEM("HTLoadFILE");
359: file->state = FS_BEGIN;
360: file->net = net;
361: HTNet_setContext(net, file);
362: HTNet_setEventCallback(net, FileEvent);
363: HTNet_setEventParam(net, file); /* callbacks get http* */
364:
1.140 frystyk 365: return FileEvent(soc, file, HTEvent_BEGIN); /* get it started - ops is ignored */
1.134 frystyk 366: }
367:
1.140 frystyk 368: PRIVATE int ReturnEvent (HTTimer * timer, void * param, HTEventType type)
369: {
370: file_info * file = (file_info *) param;
1.141 frystyk 371: if (timer != file->timer)
1.153 frystyk 372: HTDEBUGBREAK("File timer %p not in sync\n" _ timer);
373: HTTRACE(PROT_TRACE, "HTLoadFile.. Continuing %p with timer %p\n" _ file _ timer);
1.140 frystyk 374:
375: /*
376: ** Delete the timer
377: */
1.150 frystyk 378: HTTimer_delete(file->timer);
1.140 frystyk 379: file->timer = NULL;
380:
381: /*
382: ** Now call the event again
383: */
384: return FileEvent(INVSOC, file, HTEvent_READ);
385: }
386:
387:
1.134 frystyk 388: PRIVATE int FileEvent (SOCKET soc, void * pVoid, HTEventType type)
389: {
390: file_info *file = pVoid; /* Specific access information */
1.80 frystyk 391: int status = HT_ERROR;
1.134 frystyk 392: HTNet * net = file->net;
393: HTRequest * request = HTNet_request(net);
1.124 frystyk 394: HTParentAnchor * anchor = HTRequest_anchor(request);
1.45 luotonen 395:
1.91 frystyk 396: /*
397: ** Initiate a new file structure and bind to request structure
398: ** This is actually state FILE_BEGIN, but it can't be in the state
399: ** machine as we need the structure first.
400: */
1.134 frystyk 401: if (type == HTEvent_CLOSE) { /* Interrupted */
1.107 frystyk 402: HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
1.131 frystyk 403: NULL, 0, "HTLoadFile");
1.107 frystyk 404: FileCleanup(request, HT_INTERRUPTED);
1.91 frystyk 405: return HT_OK;
1.134 frystyk 406: }
407:
1.36 luotonen 408:
1.80 frystyk 409: /* Now jump into the machine. We know the state from the previous run */
410: while (1) {
411: switch (file->state) {
1.151 frystyk 412: case FS_BEGIN:
413:
414: /* We only support safe (GET, HEAD, etc) methods for the moment */
415: if (!HTMethod_isSafe(HTRequest_method(request))) {
416: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
417: NULL, 0, "HTLoadFile");
418: file->state = FS_ERROR;
419: break;
420: }
421:
422: /* Check whether we have access to local disk at all */
1.102 frystyk 423: if (HTLib_secure()) {
1.153 frystyk 424: HTTRACE(PROT_TRACE, "LoadFile.... No access to local file system\n");
1.95 frystyk 425: file->state = FS_TRY_FTP;
1.80 frystyk 426: break;
427: }
1.123 frystyk 428: file->local = HTWWWToLocal(HTAnchor_physical(anchor), "",
429: HTRequest_userProfile(request));
1.95 frystyk 430: if (!file->local) {
431: file->state = FS_TRY_FTP;
1.80 frystyk 432: break;
1.2 timbl 433: }
1.135 eric 434:
1.151 frystyk 435: /* Create a new host object and link it to the net object */
1.139 frystyk 436: {
437: HTHost * host = NULL;
1.145 frystyk 438: if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
1.139 frystyk 439: HTNet_setHost(net, host);
1.156 kahan 440: if (HTHost_addNet(host, net) == HT_PENDING) {
1.153 frystyk 441: HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
1.158 kahan 442: /* move to the hack state */
443: file->state = FS_PENDING;
444: return HT_OK;
1.156 kahan 445: }
1.139 frystyk 446: }
1.158 kahan 447: file->state = FS_DO_CN;
448: break;
449:
450: case FS_PENDING:
451: /*
452: ** 2000/08/10 JK : This is a funny state. Because of the
453: ** internal libwww stacks, when doing multiple local
454: ** requests (e.g., while using the Robot), we need to ask
455: ** again for the host object. If we had jumped directly to
456: ** the FS_DO_CN state, libwww would have blocked because
457: ** of socket starvation.
458: ** This state is similar to FS_BEGINNING, but just requests
459: ** the host object.
460: ** YES. THIS IS AN UGLY HACK!!
461: */
462: {
463: HTHost * host = NULL;
464: if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
465: HTNet_setHost(net, host);
466: if (HTHost_addNet(host, net) == HT_PENDING) {
467: HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
468: file->state = FS_PENDING;
469: return HT_OK;
470: }
471: }
472: file->state = FS_DO_CN;
1.86 frystyk 473: break;
474:
1.151 frystyk 475: case FS_DO_CN:
1.80 frystyk 476: /*
477: ** If we have to do content negotiation then find the object that
478: ** fits best into either what the client has indicated in the
1.86 frystyk 479: ** accept headers or what the client has registered on its own.
1.80 frystyk 480: ** The object chosen can in fact be a directory! However, content
1.134 frystyk 481: ** negotiation only makes sense if we can read the directory!
1.80 frystyk 482: ** We stat the file in order to find the size and to see it if
483: ** exists.
484: */
1.132 frystyk 485: if (HTRequest_negotiation(request) &&
486: HTMethod_isSafe(HTRequest_method(request))) {
1.125 frystyk 487: char * conneg = HTMulti(request, file->local,&file->stat_info);
488: if (conneg) {
489: HT_FREE(file->local);
490: file->local = conneg;
491: HTAnchor_setPhysical(anchor, conneg);
1.153 frystyk 492: HTTRACE(PROT_TRACE, "Load File... Found `%s\'\n" _ conneg);
1.80 frystyk 493: } else {
1.153 frystyk 494: HTTRACE(PROT_TRACE, "Load File... Not found - even tried content negotiation\n");
1.142 frystyk 495: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
1.126 frystyk 496: NULL, 0, "HTLoadFile");
1.125 frystyk 497: file->state = FS_ERROR;
498: break;
1.80 frystyk 499: }
1.125 frystyk 500: } else {
501: if (HT_STAT(file->local, &file->stat_info) == -1) {
1.153 frystyk 502: HTTRACE(PROT_TRACE, "Load File... Not found `%s\'\n" _ file->local);
1.125 frystyk 503: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
504: NULL, 0, "HTLoadFile");
505: file->state = FS_ERROR;
506: break;
1.80 frystyk 507: }
1.125 frystyk 508: }
509:
510: /*
1.154 frystyk 511: ** Check to see if the 'localname' is in fact a directory.
512: ** Note that we can't do a HEAD on a directory
1.125 frystyk 513: */
514: if (((file->stat_info.st_mode) & S_IFMT) == S_IFDIR) {
1.154 frystyk 515: if (HTRequest_method(request) == METHOD_GET)
516: file->state = FS_PARSE_DIR;
517: else {
518: HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
519: NULL, 0, "HTLoadFile");
520: file->state = FS_NO_DATA;
521: }
1.125 frystyk 522: break;
523: }
524:
525: /*
1.132 frystyk 526: ** If empty file then only serve it if it is editable. We also get
527: ** the bindings for the file suffixes in lack of better bindings
1.125 frystyk 528: */
529: {
530: BOOL editable = HTEditable(file->local, &file->stat_info);
1.143 frystyk 531: if (file_suffix_binding) HTBind_getAnchorBindings(anchor);
1.133 frystyk 532: if (editable) HTAnchor_appendAllow(anchor, METHOD_PUT);
1.147 frystyk 533:
534: /* Set the file size */
1.125 frystyk 535: if (file->stat_info.st_size)
536: HTAnchor_setLength(anchor, file->stat_info.st_size);
1.147 frystyk 537:
538: /* Set the file last modified time stamp */
539: if (file->stat_info.st_mtime > 0)
540: HTAnchor_setLastModified(anchor, file->stat_info.st_mtime);
541:
542: /* Check to see if we can edit it */
1.125 frystyk 543: if (!editable && !file->stat_info.st_size) {
1.147 frystyk 544: HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
1.125 frystyk 545: NULL, 0, "HTLoadFile");
546: file->state = FS_NO_DATA;
1.151 frystyk 547: } else {
548: file->state = (HTRequest_method(request)==METHOD_GET) ?
549: FS_NEED_OPEN_FILE : FS_GOT_DATA;
550: }
1.2 timbl 551: }
1.80 frystyk 552: break;
1.61 frystyk 553:
1.95 frystyk 554: case FS_NEED_OPEN_FILE:
1.146 frystyk 555: status = HTFileOpen(net, file->local, HT_FB_RDONLY);
1.120 frystyk 556: if (status == HT_OK) {
557: /*
558: ** Create the stream pipe FROM the channel to the application.
559: ** The target for the input stream pipe is set up using the
1.132 frystyk 560: ** stream stack.
1.120 frystyk 561: */
1.139 frystyk 562: {
563: HTStream * rstream = HTStreamStack(HTAnchor_format(anchor),
564: HTRequest_outputFormat(request),
565: HTRequest_outputStream(request),
566: request, YES);
567: HTNet_setReadStream(net, rstream);
568: HTRequest_setOutputConnected(request, YES);
569: }
1.126 frystyk 570:
1.120 frystyk 571: /*
572: ** Create the stream pipe TO the channel from the application
573: ** and hook it up to the request object
574: */
575: {
576: HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
577: HTRequest_setInputStream(request, (HTStream *) output);
578: }
1.80 frystyk 579:
1.120 frystyk 580: /*
581: ** Set up concurrent read/write if this request isn't the
582: ** source for a PUT or POST. As source we don't start reading
583: ** before all destinations are ready. If destination then
584: ** register the input stream and get ready for read
585: */
1.139 frystyk 586: if (HTRequest_isSource(request) && !HTRequest_destinationsReady(request))
1.120 frystyk 587: return HT_OK;
1.139 frystyk 588: HTRequest_addError(request, ERR_INFO, NO, HTERR_OK, NULL, 0,
589: "HTLoadFile");
1.120 frystyk 590: file->state = FS_NEED_BODY;
1.106 frystyk 591:
1.120 frystyk 592: /* If we are _not_ using preemptive mode and we are Unix fd's
593: ** then return here to get the same effect as when we are
594: ** connecting to a socket. That way, HTFile acts just like any
595: ** other protocol module even though we are in fact doing
596: ** blocking connect
597: */
1.148 frystyk 598: if (HTEvent_isCallbacksRegistered()) {
599: if (!HTRequest_preemptive(request)) {
600: if (!HTNet_preemptive(net)) {
1.153 frystyk 601: HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
1.148 frystyk 602: HTHost_register(HTNet_host(net), net, HTEvent_READ);
603: } else if (!file->timer) {
1.153 frystyk 604: HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
1.148 frystyk 605: file->timer =
606: HTTimer_new(NULL, ReturnEvent, file, 1, YES, NO);
607: }
608: return HT_OK;
1.140 frystyk 609: }
1.120 frystyk 610: }
1.131 frystyk 611: } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
1.120 frystyk 612: return HT_OK;
1.126 frystyk 613: else {
614: HTRequest_addError(request, ERR_INFO, NO, HTERR_INTERNAL,
615: NULL, 0, "HTLoadFile");
1.120 frystyk 616: file->state = FS_ERROR; /* Error or interrupt */
1.126 frystyk 617: }
1.107 frystyk 618: break;
1.82 frystyk 619:
1.95 frystyk 620: case FS_NEED_BODY:
1.139 frystyk 621: status = HTHost_read(HTNet_host(net), net);
1.80 frystyk 622: if (status == HT_WOULD_BLOCK)
1.91 frystyk 623: return HT_OK;
1.108 frystyk 624: else if (status == HT_LOADED || status == HT_CLOSED) {
1.95 frystyk 625: file->state = FS_GOT_DATA;
1.126 frystyk 626: } else {
627: HTRequest_addError(request, ERR_INFO, NO, HTERR_FORBIDDEN,
628: NULL, 0, "HTLoadFile");
1.95 frystyk 629: file->state = FS_ERROR;
1.126 frystyk 630: }
1.80 frystyk 631: break;
1.1 timbl 632:
1.95 frystyk 633: case FS_PARSE_DIR:
634: status = HTFile_readDir(request, file);
635: if (status == HT_LOADED)
636: file->state = FS_GOT_DATA;
1.127 frystyk 637: else
1.95 frystyk 638: file->state = FS_ERROR;
1.80 frystyk 639: break;
640:
1.95 frystyk 641: case FS_TRY_FTP:
1.80 frystyk 642: {
1.99 frystyk 643: char *url = HTAnchor_physical(anchor);
1.80 frystyk 644: HTAnchor *anchor;
645: char *newname = NULL;
646: StrAllocCopy(newname, "ftp:");
647: if (!strncmp(url, "file:", 5))
648: StrAllocCat(newname, url+5);
649: else
650: StrAllocCat(newname, url);
651: anchor = HTAnchor_findAddress(newname);
1.109 frystyk 652: HTRequest_setAnchor(request, anchor);
1.110 frystyk 653: HT_FREE(newname);
1.91 frystyk 654: FileCleanup(request, HT_IGNORE);
1.97 frystyk 655: return HTLoad(request, YES);
1.80 frystyk 656: }
657: break;
1.1 timbl 658:
1.95 frystyk 659: case FS_GOT_DATA:
1.107 frystyk 660: FileCleanup(request, HT_LOADED);
1.91 frystyk 661: return HT_OK;
1.80 frystyk 662: break;
663:
1.95 frystyk 664: case FS_NO_DATA:
1.107 frystyk 665: FileCleanup(request, HT_NO_DATA);
1.91 frystyk 666: return HT_OK;
1.80 frystyk 667: break;
668:
1.95 frystyk 669: case FS_RETRY:
1.107 frystyk 670: FileCleanup(request, HT_RETRY);
1.91 frystyk 671: return HT_OK;
1.80 frystyk 672: break;
673:
1.95 frystyk 674: case FS_ERROR:
1.107 frystyk 675: FileCleanup(request, HT_ERROR);
1.91 frystyk 676: return HT_OK;
1.80 frystyk 677: break;
678: }
679: } /* End of while(1) */
1.1 timbl 680: }
1.159 ! vbancrof 681:
! 682:
! 683: /* Calculate the required buffer size (in bytes) for directory
! 684: ** entries read from the given directory handle. Return -1 if this
! 685: ** this cannot be done.
! 686: */
! 687: PUBLIC size_t HTFile_dirent_buf_size(DIR * dirp)
! 688: {
! 689: long name_max;
! 690: #if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
! 691: name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
! 692: if (name_max == -1)
! 693: #if defined(NAME_MAX)
! 694: name_max = NAME_MAX;
! 695: #else
! 696: return (size_t)(-1);
! 697: #endif
! 698: #else
! 699: #if defined(NAME_MAX)
! 700: name_max = NAME_MAX;
! 701: #else
! 702: #error "buffer size for readdir_r cannot be determined"
! 703: #endif
! 704: #endif
! 705: return (size_t)offsetof(struct dirent, d_name) + name_max + 1;
! 706: }
Webmaster