1
0
Files
2022-09-29 17:59:04 +03:00

272 lines
7.2 KiB
C

#ident "$Revision: 1.3 $"
/*
* [Lifted from mkfs]
* Now a new function efs_newregfile(). This creates a new regular file
* of the given size; this file may have indirect extents.
* This is done to avoid rehacking the
* whole of libefs to know about indirect extents!
* Basically to get round the size limitations when a mkfs proto specifies
* a humongo file! Rather than successive extends, we allocate the space
* all at once (since we're working from a regular file we already
* know the size).
*
* Assumptions:
*
* efs_mknod has been called to allocate & initialize the dinode.
*
* The bitmap is in core and is correctly representative of blocks
* used so far.
*/
#include "libefs.h"
static extent *findex(EFS_MOUNT *mp, efs_daddr_t block, int nblocks);
static void busyout(EFS_MOUNT *mp, efs_daddr_t bn, int len);
void
efs_newregfile(EFS_MOUNT *mp, efs_ino_t ino, char *name)
{
struct stat sb;
int len;
efs_daddr_t blocks, allocblocks;
int fd;
struct efs_dinode *di;
struct extent *exbase = NULL;
struct extent *ex, *foundex;
int extents, exbufsize;
int copysize, copyoffset, copied;
char *copybuf = NULL;
static efs_daddr_t curblock = 2; /* starting place to search for
* free blocks */
int largestextent;
int i;
int numindirs = 0;
int indirblocks;
if ((fd = open(name, O_RDONLY)) < 0) {
fprintf(stderr,"%s: can't open %s: %s\n", mp->m_progname, name,
strerror(errno));
exit(1);
}
if (fstat(fd, &sb) < 0) {
fprintf(stderr,"%s: cannot stat %s: %s\n", mp->m_progname, name,
strerror(errno));
exit(1);
}
if ((sb.st_mode & S_IFMT) != S_IFREG) {
fprintf(stderr,"%s: %s is not a regular file\n",
mp->m_progname, name);
exit(1);
}
len = sb.st_size;
blocks = (len + (EFS_BBSIZE - 1)) / EFS_BBSIZE;
di = efs_iget(mp, ino);
/* Guess at number of extents & allocate space for them. We will
* realloc later if it turns out we need more; however since it's
* assumed we're creating in a virgin fs that is unlikely.
*/
exbufsize = blocks / 64;
exbase = (struct extent *)
malloc(EFS_BBSIZE + exbufsize * sizeof (struct extent));
/* now allocate extent space from the bitmap until we've got enough
* extents to hold the file.
*/
allocblocks = 0;
extents = 0;
largestextent = 0;
while (allocblocks < blocks) {
if ((foundex = findex(mp, curblock, (blocks - allocblocks)))
== NULL) {
fprintf(stderr,
"%s: cannot allocate space for file: %s\n",
mp->m_progname, name);
exit(1);
}
if (foundex->ex_length > largestextent)
largestextent = foundex->ex_length;
curblock = foundex->ex_bn + foundex->ex_length;
ex = (exbase + extents);
ex->ex_magic = 0;
ex->ex_bn = foundex->ex_bn;
ex->ex_length = foundex->ex_length;
ex->ex_offset = allocblocks;
allocblocks += foundex->ex_length;
if (++extents == exbufsize) {
exbufsize += 10;
if ((exbase = (struct extent *)realloc((char *)exbase, (EFS_BBSIZE + exbufsize * sizeof (struct extent)))) == NULL) {
fprintf(stderr,
"%s: cannot allocate space for file: %s\n",
mp->m_progname, name);
exit(1);
}
}
}
if (extents > EFS_DIRECTEXTENTS) {
indirblocks = ((EFS_BBSIZE - 1 + (extents * sizeof(struct extent))) / EFS_BBSIZE);
allocblocks = 0;
while (allocblocks < indirblocks) {
foundex = findex(mp, curblock,
(indirblocks - allocblocks));
if (foundex == NULL) {
fprintf(stderr,
"%s: cannot allocate space for file: %s\n",
mp->m_progname, name);
exit(1);
}
curblock = foundex->ex_bn + foundex->ex_length;
ex = &di->di_u.di_extents[numindirs];
ex->ex_magic = 0;
ex->ex_bn = foundex->ex_bn;
ex->ex_length = foundex->ex_length;
allocblocks += foundex->ex_length;
if (++numindirs == EFS_DIRECTEXTENTS) {
fprintf(stderr,
"%s: cannot allocate space for file: %s\n",
mp->m_progname, name);
exit(1);
}
}
di->di_u.di_extents[0].ex_offset = numindirs;
}
/* Hokay. Now we've allocated all the extents needed to hold the new
* file's data (including indirect ones if any). Copy the data to the
* appropriate places.
*/
if ((copybuf = (char *)malloc(largestextent * EFS_BBSIZE)) == NULL) {
fprintf(stderr,"%s: can't get buffer memory for file copy\n",
mp->m_progname);
exit(1);
}
for (i = 0, ex = exbase, copied = 0; i < extents; i++) {
copysize = ex->ex_length * EFS_BBSIZE;
copyoffset = ex->ex_bn * EFS_BBSIZE;
bzero(copybuf, copysize);
if ((len - copied) < copysize) /* partial last block */
copysize = len - copied;
if (read(fd, copybuf, copysize) != copysize) {
fprintf(stderr, "%s: error reading %s: %s\n",
mp->m_progname, name, strerror(errno));
exit(1);
}
/* set copysize back to EFS_BBSIZE multiple: we may be working
* on a raw device!
*/
copysize = ex->ex_length * EFS_BBSIZE;
lseek(mp->m_fd, copyoffset, SEEK_SET);
if (write(mp->m_fd, copybuf, copysize) != copysize) {
fprintf(stderr, "%s: error writing %s: %s\n",
mp->m_progname, name, strerror(errno));
exit(1);
}
copied += copysize;
ex++;
}
free (copybuf);
copybuf = NULL;
/*
* Data copied. Now the extents: if < EFS_DIRECTEXTENTS, they go
* in the dinode. If greater, they must be written to the indirect
* extents allocated for them; pointers to these are already in
* the dinode in that case.
*/
if (extents <= EFS_DIRECTEXTENTS) {
for (i = 0, foundex = exbase, ex = di->di_u.di_extents;
i < extents;
i++, ex++, foundex++) {
ex->ex_bn = foundex->ex_bn;
ex->ex_length = foundex->ex_length;
ex->ex_offset = foundex->ex_offset;
ex->ex_magic = 0;
}
} else {
copybuf = (char *)exbase;
ex = di->di_u.di_extents;
for (i = 0; i < numindirs; i++, ex++) {
if (efs_writeb(mp->m_fd, copybuf, ex->ex_bn,
ex->ex_length) != ex->ex_length) {
fprintf(stderr, "%s: error writing %s: %s\n",
mp->m_progname, name, strerror(errno));
exit(1);
}
copybuf += ex->ex_length * EFS_BBSIZE;
}
copybuf = NULL;
}
/* Busy out the appropriate parts of the bitmap. */
for (i = 0, ex = exbase; i < extents; i++, ex++)
busyout(mp, ex->ex_bn, ex->ex_length);
if (numindirs)
for (i = 0, ex = di->di_u.di_extents; i < numindirs; i++, ex++)
busyout(mp, ex->ex_bn, ex->ex_length);
di->di_size = len;
di->di_numextents = extents;
efs_iput(mp, di, ino);
close (fd);
if (exbase)
free ((char *)exbase);
if (copybuf)
free ((char *)copybuf);
return;
}
static struct extent *
findex(EFS_MOUNT *mp, efs_daddr_t block, int nblocks)
{
static struct extent ex;
efs_daddr_t nextblock = block;
int foundblocks = 0;
if (nblocks > EFS_MAXEXTENTLEN)
nblocks = EFS_MAXEXTENTLEN;
/* first skip any nonfree blocks */
while (!btst(mp->m_bitmap, nextblock)) {
nextblock++; /* side effect warning: btst is a macro! */
if (nextblock == (mp->m_fs->fs_size - 1))
return (NULL);
}
block = nextblock;
while ((foundblocks < nblocks) &&
(nextblock < mp->m_fs->fs_size) &&
btst(mp->m_bitmap, nextblock)) {
foundblocks++;
nextblock++;
}
if (!foundblocks)
return (NULL);
ex.ex_bn = block;
ex.ex_length = foundblocks;
return (&ex);
}
static void
busyout(EFS_MOUNT *mp, efs_daddr_t bn, int len)
{
while (len--) {
bclr(mp->m_bitmap, bn);
bn++; /* can't do it inside bclr: side effects!! */
mp->m_fs->fs_tfree--;
}
}