/* $NetBSD: tftp.c,v 1.38 2022/08/07 05:51:55 rin Exp $ */
/*
* Copyright (c) 1996
* Matthias Drochner. All rights reserved.
*
* 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.
*
* 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.
*
*/
/*
* Simple TFTP implementation for libsa.
* Assumes:
* - socket descriptor (int) at open_file->f_devdata
* - server host IP in global servip
* Restrictions:
* - read only
* - lseek only with SEEK_SET or SEEK_CUR
* - no big time differences between transfers (<tftp timeout)
*/
/*
* XXX Does not currently implement:
* XXX
* XXX LIBSA_NO_FS_CLOSE
* XXX LIBSA_NO_FS_SEEK
* XXX LIBSA_NO_FS_WRITE
* XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
* XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?)
*/
if (tftpfile->currblock > needblock) { /* seek backwards */
#ifndef TFTP_NOTERMINATE
tftp_terminate(tftpfile);
#endif
tftp_makereq(tftpfile); /* no error check, it worked
* for open */
}
while (tftpfile->currblock < needblock) {
int res;
#if !defined(LIBSA_NO_TWIDDLE)
if (!(tc++ % 16))
twiddle();
#endif
res = tftp_getnextblock(tftpfile);
if (res) { /* no answer */
#ifdef DEBUG
printf("%s: read error (block %d->%d)\n",
__func__, tftpfile->currblock, needblock);
#endif
return res;
}
if (tftpfile->islastblock)
break;
}
if (tftpfile->currblock == needblock) {
size_t offinblock, inbuffer;
if (tftpfile->currblock > 1) { /* move to start of file */
#ifndef TFTP_NOTERMINATE
tftp_terminate(tftpfile);
#endif
tftp_makereq(tftpfile); /* no error check, it worked
* for open */
}
/* start with the size of block 1 */
filesize = tftpfile->validsize;
/* and keep adding the sizes till we hit the last block */
while (!tftpfile->islastblock) {
int res;
res = tftp_getnextblock(tftpfile);
if (res) { /* no answer */
#ifdef DEBUG
printf("%s: read error (block %d)\n",
__func__, tftpfile->currblock);
#endif
return -1;
}
filesize += tftpfile->validsize;
}
#ifdef DEBUG
printf("%s: file is %zu bytes\n", __func__, filesize);
#endif
return filesize;
}
__compactcall int
tftp_stat(struct open_file *f, struct stat *sb)
{
struct tftp_handle *tftpfile;
tftpfile = (struct tftp_handle *)f->f_fsdata;