📄 tftplib.c
字号:
/* $Id: tftplib.c,v 1.5 2002/08/15 09:00:45 pefo Exp $ *//* * Copyright (c) 2001-2002 Opsycon AB (www.opsycon.se / www.opsycon.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#undef _KERNEL#include <sys/types.h>#include <sys/param.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/file.h>#include <sys/time.h>#include <sys/syslog.h>#include <sys/endian.h>#include <netinet/in.h>#include <arpa/tftp.h>#include <stdio.h>#include <errno.h>#include <netdb.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <file.h>#include "netio.h"#include <pmon.h>extern void log __P((int kind, const char *fmt, ...));extern in_addr_t inet_addr __P((const char *));#ifdef TFTPDBGstatic int tftptrace;#endifstatic const char spinner[] = "-\\|/";static const int tftperrmap[] = { EIO, /* EUNDEF not defined */ ENOENT, /* ENOTFOUND file not found */ EACCES, /* EACCESS access violation */ ENOSPC, /* ENOSPACE disk full or allocation exceeded */ EIO, /* EBADOP illegal TFTP operation */ EINVAL, /* EBADID unknown transfer ID */ EEXIST, /* EEXISTS file already exists */ EACCES /* ENOUSER no such user */};#define TIMEOUT 2 /* secs between rexmts */#define MAXREXMT 10 /* no of rexmts */#define PKTSIZE (SEGSIZE+4)struct tftpfile { struct sockaddr_in sin; u_short block; short flags; short eof; int sock; int start; int end; int foffs; char buf[PKTSIZE];};static int tftpopen (int, struct Url *, int, int);static int tftpread (int, void *, int);static int tftpwrite (int, const void *, int);static off_t tftplseek (int, long, int);static int tftpioctl (int, int, void *);static int tftpclose (int);static NetFileOps tftpops = { "tftp", tftpopen, tftpread, tftpwrite, tftplseek, tftpioctl, tftpclose};static void init_netfs __P((void)) __attribute__ ((constructor));static void init_netfs(){ /* * Install ram based file system. */ netfs_init(&tftpops);}static int tftprrq (struct tftpfile *tfp, struct tftphdr *req, int size);static int tftpwrq (struct tftpfile *tfp, struct tftphdr *req, int size);static void tftpnxtblk (struct tftpfile *tfp);static int makerequest (int request, const char *name, struct tftphdr *tp, const char *mode);#ifdef TFTPDBGstatic void tpacket (char *s, struct tftphdr *tp, int n);#endifstatic int synchnet (int f);static inttftpopen (int fd, struct Url *url, int flags, int perms){ struct hostent *hp; struct servent *sp; const char *mode; char *host; char hbuf[MAXHOSTNAMELEN]; char reqbuf[PKTSIZE]; struct tftpfile *tfp; struct tftphdr *rp; int oflags, size; NetFile *nfp = (NetFile *)_file[fd].data; oflags = flags & O_ACCMODE; if (oflags != O_RDONLY && oflags != O_WRONLY) { errno = EACCES; return -1; } sp = getservbyname("tftp", "udp"); if (!sp) { errno = EPROTONOSUPPORT; return -1; }#ifdef TFTPDBG tftptrace = getenv ("tftptrace") ? 1 : 0;#endif if (strlen(url->hostname) != 0) { host = url->hostname; } else { host = getenv ("tftphost"); if (!host) { log (LOG_INFO, "tftp: missing/bad host name: %s\n", url->filename); errno = EDESTADDRREQ; return -1; } } tfp = (struct tftpfile *) malloc (sizeof (struct tftpfile)); if (!tfp) { errno = ENOBUFS; return -1; } bzero (tfp, sizeof (struct tftpfile)); nfp->data = (void *)tfp; tfp->sock = socket(AF_INET, SOCK_DGRAM, 0); if (tfp->sock < 0) goto error; tfp->sin.sin_family = AF_INET; if (bind(tfp->sock, (struct sockaddr *)&tfp->sin, sizeof (tfp->sin)) < 0) goto error; hp = gethostbyname(host); if (hp) { tfp->sin.sin_family = hp->h_addrtype; bcopy(hp->h_addr, (void *)&tfp->sin.sin_addr, hp->h_length); strncpy (hbuf, hp->h_name, sizeof(hbuf) - 1); hbuf[sizeof(hbuf)-1] = '\0'; host = hbuf; } else { tfp->sin.sin_family = AF_INET; tfp->sin.sin_addr.s_addr = inet_addr (host); if (tfp->sin.sin_addr.s_addr == -1) { log (LOG_INFO, "tftp: bad internet address: %s\n", host); errno = EADDRNOTAVAIL; goto error; } } tfp->sin.sin_port = sp->s_port; rp = (struct tftphdr *)reqbuf; tfp->flags = flags; mode = "octet"; if (oflags == O_RDONLY) { tfp->block = 1; size = makerequest(RRQ, url->filename, rp, mode); size = tftprrq (tfp, rp, size); tfp->end = tfp->start + size; } else { tfp->block = 0; size = makerequest(WRQ, url->filename, rp, mode); size = tftpwrq (tfp, rp, size - 4); } if (size >= 0) return 0;error: if (tfp->sock >= 0) close (tfp->sock); free (tfp); return -1;}static inttftpread (fd, buf, nread) int fd; void *buf; int nread;{ NetFile *nfp; struct tftpfile *tfp; struct tftphdr *rp; int nb, n; nfp = (NetFile *)_file[fd].data; tfp = (struct tftpfile *)nfp->data; if ((tfp->flags & O_ACCMODE) != O_RDONLY) { errno = EPERM; return (-1); } rp = (struct tftphdr *) tfp->buf; /* continue while more bytes wanted, and more available */ for (nb = nread; nb != 0 && tfp->start < tfp->end; ) { if (tfp->foffs >= tfp->start && tfp->foffs < tfp->end) { /* got some data that's in range */ n = tfp->end - tfp->foffs; if (n > nb) n = nb; bcopy (&rp->th_data[tfp->foffs - tfp->start], buf, n); tfp->foffs += n; buf += n; nb -= n; } if (tfp->foffs >= tfp->end) { /* buffer is empty, ack last packet and refill */ struct tftphdr ack; ack.th_opcode = htons((u_short)ACK); ack.th_block = htons((u_short)tfp->block); tftpnxtblk (tfp); n = tftprrq (tfp, &ack, 4); if (n < 0) return (-1); tfp->start = tfp->end; tfp->end = tfp->start + n; } } return nread - nb;}static inttftpwrite (fd, buf, nwrite) int fd; const void *buf; int nwrite;{ NetFile *nfp; struct tftpfile *tfp; struct tftphdr *dp; int nb, n; nfp = (NetFile *)_file[fd].data; tfp = (struct tftpfile *)nfp->data; if ((tfp->flags & O_ACCMODE) != O_WRONLY) { errno = EPERM; return (-1); } dp = (struct tftphdr *)tfp->buf; for (nb = nwrite; nb != 0; ) { n = SEGSIZE - tfp->end; if (n > nb) n = nb; bcopy (buf, &dp->th_data[tfp->end], n); tfp->end += n; tfp->foffs += n; buf += n; nb -= n; if (tfp->end == SEGSIZE) { /* buffer is full, send it */ tftpnxtblk (tfp); dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)tfp->block); n = tftpwrq (tfp, dp, tfp->end); if (n < 0) return (-1); tfp->end = 0; } } return nwrite - nb;}static off_ttftplseek (fd, offs, how) int fd; long offs; int how;{ NetFile *nfp; struct tftpfile *tfp; long noffs; nfp = (NetFile *)_file[fd].data; tfp = (struct tftpfile *)nfp->data; switch (how) { case SEEK_SET: noffs = offs; break; case SEEK_CUR: noffs = tfp->foffs + offs; break; case SEEK_END: default: return -1; } if ((tfp->flags & O_ACCMODE) == O_WRONLY) { if (noffs != tfp->foffs) { errno = ESPIPE; return (-1); } } else { if (noffs < tfp->start) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -