Annotation of libwww/Library/src/HTFile.c, revision 1.117

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.1       timbl       6: **
                      7: **     This is unix-specific code in general, with some VMS bits.
1.8       timbl       8: **     These are routines for file access used by browsers.
1.1       timbl       9: **
                     10: ** History:
                     11: **        Feb 91       Written Tim Berners-Lee CERN/CN
                     12: **        Apr 91       vms-vms access included using DECnet syntax
                     13: **     26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
                     14: **                     Fixed access bug for relative names on VMS.
1.28      duns       15: **        Sep 93 (MD)  Access to VMS files allows sharing.
                     16: **     15 Nov 93 (MD)  Moved HTVMSname to HTVMSUTILS.C
1.52      duns       17: **     22 Feb 94 (MD)  Excluded two routines if we are not READING directories
1.61      frystyk    18: **     18 May 94 (HF)  Directory stuff removed and stream handling updated,
                     19: **                     error messages introduced etc.
1.1       timbl      20: **
                     21: ** Bugs:
1.2       timbl      22: **     FTP: Cannot access VMS files from a unix machine.
                     23: **      How can we know that the
1.1       timbl      24: **     target machine runs VMS?
                     25: */
                     26: 
1.67      frystyk    27: /* Library Includes */
1.112     frystyk    28: #include "sysdep.h"
1.67      frystyk    29: #include "HTUtils.h"
1.75      frystyk    30: #include "HTString.h"
1.1       timbl      31: #include "HTParse.h"
                     32: #include "HTTCP.h"
                     33: #include "HTAnchor.h"
1.2       timbl      34: #include "HTAtom.h"
                     35: #include "HTWriter.h"
1.75      frystyk    36: #include "HTFWrite.h"
1.52      duns       37: #include "HTFormat.h"
1.102     frystyk    38: #include "HTWWWStr.h"
                     39: #include "HTAccess.h"
1.54      luotonen   40: #include "HTMulti.h"
1.95      frystyk    41: #include "HTIcons.h"
                     42: #include "HTDir.h"
1.78      frystyk    43: #include "HTBind.h"
1.80      frystyk    44: #include "HTSocket.h"
1.92      frystyk    45: #include "HTNetMan.h"
1.61      frystyk    46: #include "HTError.h"
1.91      frystyk    47: #include "HTReqMan.h"
1.67      frystyk    48: #include "HTFile.h"            /* Implemented here */
                     49: 
1.91      frystyk    50: /* Final states have negative value */
1.80      frystyk    51: typedef enum _FileState {
1.95      frystyk    52:     FS_RETRY           = -4,
                     53:     FS_ERROR           = -3,
                     54:     FS_NO_DATA         = -2,
                     55:     FS_GOT_DATA                = -1,
                     56:     FS_BEGIN           = 0,
                     57:     FS_DO_CN,
                     58:     FS_NEED_OPEN_FILE,
                     59:     FS_NEED_TARGET,
                     60:     FS_NEED_BODY,
                     61:     FS_PARSE_DIR,
                     62:     FS_TRY_FTP
1.80      frystyk    63: } FileState;
                     64: 
1.91      frystyk    65: /* This is the context structure for the this module */
1.77      frystyk    66: typedef struct _file_info {
1.80      frystyk    67:     FileState          state;            /* Current state of the connection */
1.95      frystyk    68:     char *             local;          /* Local representation of file name */
1.91      frystyk    69: #ifdef NO_UNIX_IO    
1.80      frystyk    70:     FILE *             fp;        /* If we can't use sockets on local files */
1.117   ! frystyk    71:     HTFileBuffer *     fbuf;
1.91      frystyk    72: #endif
1.77      frystyk    73: } file_info;
1.2       timbl      74: 
1.80      frystyk    75: /* Local definition */
                     76: struct _HTStream {
1.112     frystyk    77:     const HTStreamClass *      isa;
1.91      frystyk    78:     /* ... */
1.80      frystyk    79: };
                     80: 
1.95      frystyk    81: PRIVATE BOOL           HTTakeBackup = YES;
1.1       timbl      82: 
1.95      frystyk    83: PRIVATE HTDirReadme    dir_readme = HT_DIR_README_TOP;
                     84: PRIVATE HTDirAccess    dir_access = HT_DIR_OK;
                     85: PRIVATE HTDirShow      dir_show = HT_DS_SIZE+HT_DS_DATE+HT_DS_DES+HT_DS_ICON;
                     86: PRIVATE HTDirKey       dir_key = HT_DK_CINS;
1.2       timbl      87: 
1.61      frystyk    88: /* ------------------------------------------------------------------------- */
1.11      timbl      89: 
1.95      frystyk    90: /*     Directory Access
                     91: **     ----------------
                     92: */
                     93: PUBLIC BOOL HTFile_setDirAccess (HTDirAccess mode)
                     94: {
                     95:     dir_access = mode;
                     96:     return YES;
                     97: }
                     98: 
                     99: PUBLIC HTDirAccess HTFile_dirAccess (void)
                    100: {
                    101:     return dir_access;
                    102: }
                    103: 
                    104: /*     Directory Readme
                    105: **     ----------------
                    106: */
                    107: PUBLIC BOOL HTFile_setDirReadme (HTDirReadme mode)
                    108: {
                    109:     dir_readme = mode;
                    110:     return YES;
                    111: }
                    112: 
                    113: PUBLIC HTDirReadme HTFile_dirReadme (void)
                    114: {
                    115:     return dir_readme;
                    116: }
                    117: 
                    118: /*     HTFile_readDir
                    119: **     --------------
                    120: **     Reads the directory "path"
                    121: **     Returns:
                    122: **             HT_ERROR        Error
1.107     frystyk   123: **             HT_FORBIDDEN    Directory reading not allowed
1.95      frystyk   124: **             HT_LOADED       Successfully read the directory
1.1       timbl     125: */
1.95      frystyk   126: PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
1.1       timbl     127: {
1.112     frystyk   128: #ifdef HAVE_READDIR
                    129:     DIR * dp;
1.95      frystyk   130:     struct stat file_info;
                    131:     char *url = HTAnchor_physical(request->anchor);
                    132:     char fullname[HT_MAX_PATH+1];
                    133:     char *name;
1.111     eric      134:     if (PROT_TRACE) HTTrace("Reading..... directory\n");
1.95      frystyk   135:     if (dir_access == HT_DIR_FORBID) {
1.100     frystyk   136:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95      frystyk   137:                   NULL, 0, "HTFile_readDir");
1.107     frystyk   138:        return HT_FORBIDDEN;
1.95      frystyk   139:     }
                    140:     
                    141:     /* Initialize path name for stat() */
                    142:     if (*(name = (url+strlen(url)-1)) != '/') {
                    143:        char *newurl = NULL;
                    144:        StrAllocCopy(newurl, url);
                    145:        StrAllocCat(newurl, "/");
1.110     frystyk   146:        HT_FREE(file->local);
1.95      frystyk   147:        file->local = HTWWWToLocal(newurl, "");
1.110     frystyk   148:        HT_FREE(newurl);
1.95      frystyk   149:     }
                    150:     strcpy(fullname, file->local);
                    151:     name = fullname+strlen(fullname);           /* Point to end of fullname */
                    152: 
                    153:     /* Check if access is enabled */
                    154:     if (dir_access == HT_DIR_SELECTIVE) {
                    155:        strcpy(name, DEFAULT_DIR_FILE);
                    156:        if (HT_STAT(fullname, &file_info)) {
1.80      frystyk   157:            if (PROT_TRACE)
1.111     eric      158:                HTTrace(
1.95      frystyk   159:                        "Read dir.... `%s\' not found\n", DEFAULT_DIR_FILE);
1.100     frystyk   160:            HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95      frystyk   161:                       NULL, 0, "HTFile_readDir");
1.107     frystyk   162:            return HT_FORBIDDEN;
1.1       timbl     163:        }
                    164:     }
                    165: 
1.95      frystyk   166:     if ((dp = opendir(file->local))) {
1.112     frystyk   167:        struct dirent * dirbuf;
1.95      frystyk   168:        HTDir *dir = HTDir_new(request, dir_show, dir_key);
                    169:        char datestr[20];
                    170:        char sizestr[10];
                    171:        HTFileMode mode;
                    172: #ifdef HT_REENTRANT
1.112     frystyk   173:        struct dirent * result;                             /* For readdir_r */
                    174:        while ((dirbuf = (dirent *) readdir_r(dp, &result)))
1.95      frystyk   175: #else
                    176:        while ((dirbuf = readdir(dp)))
                    177: #endif /* HT_REENTRANT */
                    178:        {
                    179:            /* Current and parent directories are never shown in list */
1.112     frystyk   180: #ifdef HAVE_DIRENT_INO
1.95      frystyk   181:            if (!dirbuf->d_ino ||
                    182:                !strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
1.112     frystyk   183: #else
                    184:            if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
                    185: #endif
1.95      frystyk   186:                continue;
                    187: 
                    188:            /* Make a lstat on the file */
                    189:            strcpy(name, dirbuf->d_name);
                    190:            if (HT_LSTAT(fullname, &file_info)) {
                    191:                if (PROT_TRACE)
1.111     eric      192:                    HTTrace("Read dir.... lstat failed: %s\n",fullname);
1.95      frystyk   193:                continue;
                    194:            }
1.1       timbl     195: 
1.95      frystyk   196:            /* Convert stat info to fit our setup */
1.103     frystyk   197:            if (((mode_t) file_info.st_mode & S_IFMT) == S_IFDIR) {
1.95      frystyk   198: #ifdef VMS
                    199:                char *dot = strstr(name, ".DIR");      /* strip .DIR part... */
                    200:                if (dot) *dot = '\0';
                    201: #endif /* VMS */
                    202:                mode = HT_IS_DIR;
                    203:                if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
                    204:            } else {
                    205:                mode = HT_IS_FILE;
                    206:                if (dir_show & HT_DS_SIZE)
                    207:                    HTNumToStr(file_info.st_size, sizestr, 10);
                    208:            }
                    209:            if (dir_show & HT_DS_DATE)
                    210:                HTDateDirStr(&file_info.st_mtime, datestr, 20);
1.1       timbl     211: 
1.95      frystyk   212:            /* Add to the list */
                    213:            if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
                    214:                break;
                    215:        }
                    216:        closedir(dp);
                    217:        HTDir_free(dir);
1.1       timbl     218:     } else
1.100     frystyk   219:        HTRequest_addSystemError(request,  ERR_FATAL, errno, NO, "opendir");
1.95      frystyk   220:     return HT_LOADED;
1.112     frystyk   221: #else
1.114     eric      222:     return HT_ERROR;   /* needed for WWW_MSWINDOWS */
1.112     frystyk   223: #endif /* HAVE_READDIR */
1.1       timbl     224: }
                    225: 
                    226: /*     Determine write access to a file
1.2       timbl     227: **     --------------------------------
1.80      frystyk   228: **     If stat_info is NULL then the function calls stat() on it's own,
                    229: **     otherwise it uses the information found in stat_info
1.2       timbl     230: ** On exit,
                    231: **     return value    YES if file can be accessed and can be written to.
                    232: **
                    233: ** Bugs:
                    234: **     1.      No code for non-unix systems.
                    235: **     2.      Isn't there a quicker way?
1.1       timbl     236: */
1.112     frystyk   237: PRIVATE BOOL HTEditable (const char * filename, struct stat * stat_info)
1.80      frystyk   238: {
1.112     frystyk   239: #ifdef GETGROUPS_T
1.80      frystyk   240:     int i;
                    241:     uid_t myUid;
                    242:     int        ngroups;                        /* The number of groups  */
1.1       timbl     243:     struct stat        fileStatus;
1.80      frystyk   244:     struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.112     frystyk   245:     GETGROUPS_T groups[NGROUPS];
1.80      frystyk   246:     if (!stat_info) {
1.90      frystyk   247:        if (HT_STAT(filename, &fileStatus))
1.80      frystyk   248:            return NO;                            /* Can't even access file! */
                    249:     }
1.1       timbl     250:     ngroups = getgroups(NGROUPS, groups);      /* Groups to which I belong  */
                    251:     myUid = geteuid();                         /* Get my user identifier */
                    252: 
1.95      frystyk   253:     if (PROT_TRACE) {
1.1       timbl     254:         int i;
1.111     eric      255:        HTTrace(
1.19      timbl     256:            "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.80      frystyk   257:            (unsigned int) fileptr->st_mode, (int) fileptr->st_uid,
                    258:            (int) fileptr->st_gid, (int) myUid, ngroups);
1.111     eric      259:        for (i=0; i<ngroups; i++) HTTrace(" %d", (int) groups[i]);
                    260:        HTTrace(")\n");
1.1       timbl     261:     }
                    262:     
1.80      frystyk   263:     if (fileptr->st_mode & 0002)               /* I can write anyway? */
1.1       timbl     264:        return YES;
                    265:        
1.80      frystyk   266:     if ((fileptr->st_mode & 0200)              /* I can write my own file? */
                    267:      && (fileptr->st_uid == myUid))
1.1       timbl     268:        return YES;
                    269: 
1.80      frystyk   270:     if (fileptr->st_mode & 0020)               /* Group I am in can write? */
1.1       timbl     271:     {
                    272:        for (i=0; i<ngroups; i++) {
1.80      frystyk   273:             if (groups[i] == fileptr->st_gid)
1.1       timbl     274:                return YES;
                    275:        }
                    276:     }
1.111     eric      277:     if (PROT_TRACE) HTTrace("\tFile is not editable.\n");
1.1       timbl     278:     return NO;                                 /* If no excuse, can't do */
1.80      frystyk   279: #else
                    280:     /*
                    281:     ** We don't know and can't find out. Can we be sure that when opening
                    282:     ** a file in mode "a" that the file is not modified?
                    283:     */
                    284:     return NO;
1.112     frystyk   285: #endif /* GETGROUPS_T */
1.1       timbl     286: }
1.80      frystyk   287: 
1.1       timbl     288: 
1.2       timbl     289: /*     Make a save stream
                    290: **     ------------------
                    291: **
                    292: **     The stream must be used for writing back the file.
                    293: **     @@@ no backup done
                    294: */
1.101     frystyk   295: PUBLIC HTStream * HTFileSaveStream (HTRequest * request)
1.2       timbl     296: {
                    297: 
1.112     frystyk   298:     const char * addr = HTAnchor_address((HTAnchor*)request->anchor);
1.95      frystyk   299:     char * filename = HTWWWToLocal(addr, "");
1.33      timbl     300:     FILE* fp;
                    301: 
                    302: /*     @ Introduce CVS handling here one day
                    303: */
                    304: /*     Take a backup before we do anything silly   931205
                    305: */        
                    306:     if (HTTakeBackup) {
1.69      frystyk   307:        char * p;
1.110     frystyk   308:        char * backup_filename;
                    309:        if ((backup_filename = (char  *) HT_MALLOC(strlen(filename)+2)) == NULL)
                    310:            HT_OUTOFMEM("taking backup");
1.33      timbl     311:        strcpy(backup_filename, filename);
1.34      timbl     312:        for(p=backup_filename+strlen(backup_filename);; p--) {
1.33      timbl     313:            if ((*p=='/') || (p<backup_filename)) {
                    314:                p[1]=',';               /* Insert comma after slash */
                    315:                break;
                    316:            }
                    317:            p[1] = p[0];        /* Move up everything to the right of it */
                    318:        }
                    319:        
1.65      duns      320: 
                    321: #ifdef VMS
                    322:        if ((fp=fopen(filename, "r", "shr=put", "shr=upd"))) {  /* File exists */
                    323: #else /* not VMS */
1.35      luotonen  324:        if ((fp=fopen(filename, "r"))) {                /* File exists */
1.65      duns      325: #endif /* not VMS */
1.33      timbl     326:            fclose(fp);
1.111     eric      327:            if (PROT_TRACE) HTTrace("File `%s' exists\n", filename);
1.83      frystyk   328:            if (REMOVE(backup_filename)) {
1.111     eric      329:                if (PROT_TRACE) HTTrace("Backup file `%s' removed\n",
1.56      frystyk   330:                                   backup_filename);
1.33      timbl     331:            }
                    332:            if (rename(filename, backup_filename)) {    /* != 0 => Failure */
1.111     eric      333:                if (PROT_TRACE) HTTrace("Rename `%s' to `%s' FAILED!\n",
1.56      frystyk   334:                                   filename, backup_filename);
1.33      timbl     335:            } else {                                    /* Success */
1.95      frystyk   336:                if (PROT_TRACE)
1.111     eric      337:                    HTTrace("Renamed `%s' to `%s'\n", filename,
1.95      frystyk   338:                            backup_filename);
1.33      timbl     339:            }
                    340:        }
1.110     frystyk   341:        HT_FREE(backup_filename);
1.33      timbl     342:     } /* if take backup */    
1.2       timbl     343:     
1.89      frystyk   344:     if ((fp = fopen(filename, "wb")) == NULL) {
1.100     frystyk   345:        HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
1.61      frystyk   346:        return NULL;
                    347:     } else
1.108     frystyk   348:        return HTFWriter_new(request, fp, NO);
1.2       timbl     349: }
                    350: 
1.10      secret    351: 
1.91      frystyk   352: /*     FileCleanup
                    353: **     -----------
1.80      frystyk   354: **      This function closes the connection and frees memory.
1.91      frystyk   355: **      Returns YES on OK, else NO
1.80      frystyk   356: */
1.91      frystyk   357: PRIVATE int FileCleanup (HTRequest *req, int status)
1.80      frystyk   358: {
1.91      frystyk   359:     HTNet *net = req->net;
                    360:     file_info *file = (file_info *) net->context;
1.106     frystyk   361: 
                    362:     /* Free stream with data TO Local file system */
1.107     frystyk   363:     if (HTRequest_isDestination(req))
                    364:        HTRequest_removeDestination(req);
                    365:     else  if (req->input_stream) {
1.106     frystyk   366:        if (status == HT_INTERRUPTED)
                    367:            (*req->input_stream->isa->abort)(req->input_stream, NULL);
                    368:        else
                    369:            (*req->input_stream->isa->_free)(req->input_stream);
                    370:        req->input_stream = NULL;
                    371:     }
                    372: 
1.91      frystyk   373:     if (file) {
                    374: #ifdef NO_UNIX_IO
1.117   ! frystyk   375:        HTFileBuffer_delete(file->fbuf);
1.91      frystyk   376:        if (file->fp) {
1.80      frystyk   377:            if (PROT_TRACE)
1.111     eric      378:                HTTrace("FileCleanup. Closing file %p\n", file->fp);
1.113     eric      379: #ifdef WWW_WIN_DLL
                    380:            HTSocket_DLLHackFclose(file->fp);
                    381: #else
                    382:            close(file->fp);
                    383: #endif
1.91      frystyk   384:        }
1.82      frystyk   385: #endif
1.110     frystyk   386:        HT_FREE(file->local);
                    387:        HT_FREE(file);
1.80      frystyk   388:     }
1.107     frystyk   389:     HTNet_delete(net, req->internal ? HT_IGNORE : status);
1.91      frystyk   390:     return YES;
1.80      frystyk   391: }
                    392: 
                    393: 
1.1       timbl     394: /*     Load a document
                    395: **     ---------------
                    396: **
                    397: ** On entry,
1.80      frystyk   398: **     request         This is the request structure
1.1       timbl     399: ** On exit,
1.91      frystyk   400: **     returns         HT_ERROR        Error has occured in call back
                    401: **                     HT_OK           Call back was OK
1.1       timbl     402: */
1.91      frystyk   403: PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request, SockOps ops)
1.1       timbl     404: {
1.80      frystyk   405:     int status = HT_ERROR;
1.91      frystyk   406:     HTNet *net = request->net;              /* Generic protocol information */
1.80      frystyk   407:     file_info *file;                         /* Specific access information */
1.99      frystyk   408:     HTParentAnchor *anchor = HTRequest_anchor(request);
1.45      luotonen  409: 
1.91      frystyk   410:     /*
                    411:     ** Initiate a new file structure and bind to request structure
                    412:     ** This is actually state FILE_BEGIN, but it can't be in the state
                    413:     ** machine as we need the structure first.
                    414:     */
                    415:     if (ops == FD_NONE) {
1.111     eric      416:        if (PROT_TRACE) HTTrace("HTLoadFile.. Looking for `%s\'\n",
1.99      frystyk   417:                                HTAnchor_physical(anchor));
1.110     frystyk   418:        if ((file = (file_info *) HT_CALLOC(1, sizeof(file_info))) == NULL)
                    419:            HT_OUTOFMEM("HTLoadFILE");
1.95      frystyk   420:        file->state = FS_BEGIN;
1.91      frystyk   421:        net->context = file;
                    422:     } if (ops == FD_CLOSE) {                                 /* Interrupted */
1.107     frystyk   423:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
                    424:                           NULL, 0, "HTLoadHTTP");
                    425:        FileCleanup(request, HT_INTERRUPTED);
1.91      frystyk   426:        return HT_OK;
                    427:     } else
                    428:        file = (file_info *) net->context;              /* Get existing copy */
1.36      luotonen  429: 
1.80      frystyk   430:     /* Now jump into the machine. We know the state from the previous run */
                    431:     while (1) {
                    432:        switch (file->state) {
1.95      frystyk   433:          case FS_BEGIN:
1.102     frystyk   434:            if (HTLib_secure()) {
1.80      frystyk   435:                if (PROT_TRACE)
1.111     eric      436:                    HTTrace("LoadFile.... No access to local file system\n");
1.95      frystyk   437:                file->state = FS_TRY_FTP;
1.80      frystyk   438:                break;
                    439:            }
1.99      frystyk   440:            file->local = HTWWWToLocal(HTAnchor_physical(anchor), "");
1.95      frystyk   441:            if (!file->local) {
                    442:                file->state = FS_TRY_FTP;
1.80      frystyk   443:                break;
1.2       timbl     444:            }
1.86      frystyk   445: 
                    446:            /* If cache element then jump directly to OPEN FILE state */
1.99      frystyk   447:            file->state = HTAnchor_cacheHit(anchor) ?
1.95      frystyk   448:                FS_NEED_OPEN_FILE : FS_DO_CN;
1.86      frystyk   449:            break;
                    450: 
1.95      frystyk   451:          case FS_DO_CN:
1.80      frystyk   452:            /*
                    453:            ** If we have to do content negotiation then find the object that
                    454:            ** fits best into either what the client has indicated in the
1.86      frystyk   455:            ** accept headers or what the client has registered on its own.
1.80      frystyk   456:            ** The object chosen can in fact be a directory! However, content
                    457:            ** negotiation only makes sense it we can read the directory!
                    458:            ** We stat the file in order to find the size and to see it if
                    459:            ** exists.
                    460:            */
                    461:            {
                    462:                struct stat stat_info;        /* Contains actual file chosen */
                    463:                if (request->ContentNegotiation) {
1.95      frystyk   464:                    char *new_path=HTMulti(request,file->local,&stat_info);
1.80      frystyk   465:                    if (new_path) {
1.110     frystyk   466:                        HT_FREE(file->local);
1.95      frystyk   467:                        file->local = new_path;
1.99      frystyk   468:                        HTAnchor_setPhysical(anchor, new_path);
1.80      frystyk   469:                    } else {
1.95      frystyk   470:                        file->state = FS_ERROR;
1.80      frystyk   471:                        break;
                    472:                    }
                    473:                } else {
1.95      frystyk   474:                    if (HT_STAT(file->local, &stat_info) == -1) {
1.80      frystyk   475:                        if (PROT_TRACE)
1.111     eric      476:                            HTTrace("HTLoadFile.. Can't stat %s\n",
1.95      frystyk   477:                                    file->local);
1.100     frystyk   478:                        HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
1.81      frystyk   479:                                   NULL, 0, "HTLoadFile");
1.95      frystyk   480:                        file->state = FS_ERROR;
1.80      frystyk   481:                        break;
                    482:                    }
                    483:                }
                    484:                /* Check to see if the 'localname' is in fact a directory */
                    485:                if (((stat_info.st_mode) & S_IFMT) == S_IFDIR)
1.95      frystyk   486:                    file->state = FS_PARSE_DIR;
1.80      frystyk   487:                else {
                    488:                    /*
                    489:                    ** If empty file then only serve it if it is editable
                    490:                    */
1.95      frystyk   491:                    BOOL editable = HTEditable(file->local, &stat_info);
1.99      frystyk   492:                    HTBind_getBindings(anchor);
1.80      frystyk   493:                    if (editable)
1.99      frystyk   494:                        HTAnchor_appendMethods(anchor, METHOD_PUT);
1.80      frystyk   495:                    if (stat_info.st_size)
1.99      frystyk   496:                        HTAnchor_setLength(anchor, stat_info.st_size);
1.80      frystyk   497: 
1.83      frystyk   498:                    /* Done with relevant metainformation in anchor */
1.99      frystyk   499:                    HTAnchor_setHeaderParsed(anchor);
1.80      frystyk   500: 
                    501:                    if (!editable && !stat_info.st_size) {
1.100     frystyk   502:                        HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_CONTENT,
1.80      frystyk   503:                                   NULL, 0, "HTLoadFile");
1.95      frystyk   504:                        file->state = FS_NO_DATA;
1.80      frystyk   505:                    } else
1.95      frystyk   506:                        file->state = FS_NEED_OPEN_FILE;
1.80      frystyk   507:                }
1.2       timbl     508:            }
1.80      frystyk   509:            break;
1.61      frystyk   510: 
1.95      frystyk   511:          case FS_NEED_OPEN_FILE:
1.80      frystyk   512:            /*
                    513:            ** If we have unix file descriptors then use this otherwise use
                    514:            ** the ANSI C file descriptors
                    515:            */
                    516: #ifndef NO_UNIX_IO
1.95      frystyk   517:            if ((net->sockfd = open(file->local, O_RDONLY)) == -1) {
1.100     frystyk   518:                HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "open");
1.95      frystyk   519:                file->state = FS_ERROR;
1.82      frystyk   520:                break;
                    521:            }
                    522:            if (PROT_TRACE)
1.111     eric      523:                HTTrace("HTLoadFile.. `%s' opened using socket %d \n",
1.95      frystyk   524:                        file->local, net->sockfd);
1.80      frystyk   525: 
1.82      frystyk   526:            /* If non-blocking protocol then change socket status
1.116     frystyk   527:            ** I use fcntl() so that I can ask the status before I set it.
1.82      frystyk   528:            ** See W. Richard Stevens (Advan. Prog. in UNIX env, p.364)
                    529:            ** Be CAREFULL with the old `O_NDELAY' - it wont work as read()
                    530:            ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD
                    531:            ** and does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
                    532:            */
1.112     frystyk   533: #ifdef HAVE_FCNTL
1.107     frystyk   534:            if (!request->net->preemptive) {
1.116     frystyk   535:                if ((status = fcntl(net->sockfd, F_GETFL, 0)) != -1) {
1.115     frystyk   536: #ifdef O_NONBLOCK
1.82      frystyk   537:                    status |= O_NONBLOCK;                           /* POSIX */
1.115     frystyk   538: #else
                    539: #ifdef F_NDELAY
                    540:                    status |= F_NDELAY;                               /* BSD */
                    541: #endif /* F_NDELAY */
                    542: #endif /* O_NONBLOCK */
1.116     frystyk   543:                    status = fcntl(net->sockfd, F_SETFL, status);
1.82      frystyk   544:                }
                    545:                if (PROT_TRACE) {
                    546:                    if (status == -1)
1.111     eric      547:                        HTTrace("HTLoadFile.. Can't make socket non-blocking\n");
1.82      frystyk   548:                    else
1.111     eric      549:                        HTTrace("HTLoadFile.. Using NON_BLOCKING I/O\n");
1.80      frystyk   550:                }
1.61      frystyk   551:            }
1.112     frystyk   552: #endif /* HAVE_FCNTL */
1.80      frystyk   553: #else
1.83      frystyk   554: #ifdef VMS     
1.95      frystyk   555:            if (!(file->fp = fopen(file->local,"r","shr=put","shr=upd"))) {
1.80      frystyk   556: #else
1.105     frystyk   557: #ifdef WWW_WIN_DLL
                    558:            if ((file->fp = HTSocket_DLLHackFopen(file->local,"r")) == NULL) {
                    559: #else /* !WWW_WIN_DLL */
1.95      frystyk   560:            if ((file->fp = fopen(file->local,"r")) == NULL) {
1.105     frystyk   561: #endif /* !WWW_WIN_DLL */
1.82      frystyk   562: #endif /* !VMS */
1.100     frystyk   563:                HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
1.95      frystyk   564:                file->state = FS_ERROR;
1.82      frystyk   565:                break;
1.80      frystyk   566:            }
1.82      frystyk   567:            if (PROT_TRACE)
1.111     eric      568:                HTTrace("HTLoadFile.. `%s' opened using FILE %p\n",
1.95      frystyk   569:                        file->local, file->fp);
1.80      frystyk   570: #endif /* !NO_UNIX_IO */
1.106     frystyk   571: 
                    572:            /* Set up stream TO local file system */
                    573:            request->input_stream = HTBufWriter_new(net, YES, 512);
                    574: 
1.83      frystyk   575:            /*
                    576:            ** Set up concurrent read/write if this request isn't the
                    577:            ** source for a PUT or POST. As source we don't start reading
                    578:            ** before all destinations are ready. If destination then
                    579:            ** register the input stream and get ready for read
                    580:            */
1.107     frystyk   581:            if (HTRequest_isDestination(request)) {
1.91      frystyk   582:                HTEvent_Register(net->sockfd, request, (SockOps) FD_READ,
                    583:                                 HTLoadFile, net->priority);
1.83      frystyk   584:                HTRequest_linkDestination(request);
                    585:            }
1.107     frystyk   586:            file->state = FS_NEED_TARGET;
                    587:            if (HTRequest_isSource(request) && !HTRequest_destinationsReady(request))
                    588:                return HT_OK;
1.116     frystyk   589: 
                    590: #ifndef NO_UNIX_IO
                    591:            if (PROT_TRACE) HTTrace("HTLoadFile.. returning\n");
                    592:            HTEvent_Register(net->sockfd, request, (SockOps) FD_READ,
                    593:                             net->cbf, net->priority);
                    594:            return HT_WOULD_BLOCK;
                    595: #endif
1.107     frystyk   596:            break;
1.82      frystyk   597: 
1.107     frystyk   598:          case FS_NEED_TARGET:
1.86      frystyk   599:            /*
                    600:            ** Set up read buffer and streams.
                    601:            ** If cache element, we know that it's MIME, so call MIME parser
                    602:            ** If ANSI then sockfd=INVSOC
                    603:            */
1.117   ! frystyk   604: #ifndef NO_UNIX_IO
1.116     frystyk   605:            HTChannel_new(net->sockfd, HT_CH_PLAIN, NO);
1.117   ! frystyk   606: #else
        !           607:            file->fbuf = HTFileBuffer_new();
        !           608: #endif
1.99      frystyk   609:            if (HTAnchor_cacheHit(anchor))HTAnchor_setFormat(anchor, WWW_MIME);
                    610:            net->target = HTStreamStack(HTAnchor_format(anchor),
                    611:                                        request->output_format,
                    612:                                        request->output_stream,
                    613:                                        request, YES);
1.95      frystyk   614:            file->state = net->target ? FS_NEED_BODY : FS_ERROR;
1.80      frystyk   615:            break;
1.65      duns      616: 
1.95      frystyk   617:          case FS_NEED_BODY:
1.80      frystyk   618: #ifndef NO_UNIX_IO
1.116     frystyk   619:            status = HTChannel_readSocket(request, net);
1.82      frystyk   620: #else
1.117   ! frystyk   621:            status = HTChannel_readFile(request, net, file->fbuf, file->fp);
1.82      frystyk   622: #endif
1.80      frystyk   623:            if (status == HT_WOULD_BLOCK)
1.91      frystyk   624:                return HT_OK;
1.108     frystyk   625:            else if (status == HT_LOADED || status == HT_CLOSED) {
1.95      frystyk   626:                file->state = FS_GOT_DATA;
1.61      frystyk   627:            } else
1.95      frystyk   628:                file->state = FS_ERROR;
1.80      frystyk   629:            break;
1.1       timbl     630: 
1.95      frystyk   631:          case FS_PARSE_DIR:
                    632:            status = HTFile_readDir(request, file);
                    633:            if (status == HT_LOADED)
                    634:                file->state = FS_GOT_DATA;
                    635:            else
                    636:                file->state = FS_ERROR;
1.80      frystyk   637:            break;
                    638: 
1.95      frystyk   639:          case FS_TRY_FTP:
1.80      frystyk   640:            {
1.99      frystyk   641:                char *url = HTAnchor_physical(anchor);
1.80      frystyk   642:                HTAnchor *anchor;
                    643:                char *newname = NULL;
                    644:                StrAllocCopy(newname, "ftp:");
                    645:                if (!strncmp(url, "file:", 5))
                    646:                    StrAllocCat(newname, url+5);
                    647:                else
                    648:                    StrAllocCat(newname, url);
                    649:                anchor = HTAnchor_findAddress(newname);
1.109     frystyk   650:                HTRequest_setAnchor(request, anchor);
1.110     frystyk   651:                HT_FREE(newname);
1.91      frystyk   652:                FileCleanup(request, HT_IGNORE);
1.97      frystyk   653:                return HTLoad(request, YES);
1.80      frystyk   654:            }
                    655:            break;
1.1       timbl     656: 
1.95      frystyk   657:          case FS_GOT_DATA:
1.83      frystyk   658:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   659:                if (HTRequest_isDestination(request)) {
                    660:                    HTLink *link =
                    661:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   662:                                          (HTAnchor *) anchor);
1.104     frystyk   663:                    HTLink_setResult(link, HT_LINK_OK);
1.87      frystyk   664:                }
1.107     frystyk   665:            }
                    666:            FileCleanup(request, HT_LOADED);
1.91      frystyk   667:            return HT_OK;
1.80      frystyk   668:            break;
                    669: 
1.95      frystyk   670:          case FS_NO_DATA:
1.83      frystyk   671:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   672:                if (HTRequest_isDestination(request)) {
                    673:                    HTLink *link =
                    674:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   675:                                          (HTAnchor *) anchor);
1.104     frystyk   676:                    HTLink_setResult(link, HT_LINK_OK);
1.87      frystyk   677:                }
1.107     frystyk   678:            }
                    679:            FileCleanup(request, HT_NO_DATA);
1.91      frystyk   680:            return HT_OK;
1.80      frystyk   681:            break;
                    682: 
1.95      frystyk   683:          case FS_RETRY:
1.83      frystyk   684:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   685:                if (HTRequest_isDestination(request)) {
                    686:                    HTLink *link =
                    687:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   688:                                          (HTAnchor *) anchor);
1.104     frystyk   689:                    HTLink_setResult(link, HT_LINK_ERROR);
1.87      frystyk   690:                }
1.107     frystyk   691:                HTRequest_killPostWeb(request);
                    692:            }
                    693:            FileCleanup(request, HT_RETRY);
1.91      frystyk   694:            return HT_OK;
1.80      frystyk   695:            break;
                    696: 
1.95      frystyk   697:          case FS_ERROR:
1.83      frystyk   698:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   699:                if (HTRequest_isDestination(request)) {
                    700:                    HTLink *link =
                    701:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   702:                                          (HTAnchor *) anchor);
1.104     frystyk   703:                    HTLink_setResult(link, HT_LINK_ERROR);
1.87      frystyk   704:                }
1.107     frystyk   705:                HTRequest_killPostWeb(request);
                    706:            }
                    707:            FileCleanup(request, HT_ERROR);
1.91      frystyk   708:            return HT_OK;
1.80      frystyk   709:            break;
                    710:        }
                    711:     } /* End of while(1) */
1.1       timbl     712: }

Webmaster