[comp.unix.questions] Set file size in SYSV

kevin@msa3b.UUCP (Kevin P. Kleinfelter) (08/10/89)

O.K. I give up.  How do you set the size of a file in SYSV.
In particular, I want to take a file which is 1000 bytes, and truncate
it to 500 bytes WITHOUT COPYING IT.

If you know, thanks!
	
-- 
Kevin Kleinfelter @ Management Science America, Inc (404) 239-2347
gatech!nanovx!msa3b!kevin

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/13/89)

In article <708@msa3b.UUCP> kevin@msa3b.UUCP (Kevin P. Kleinfelter) writes:
>O.K. I give up.  How do you set the size of a file in SYSV.
>In particular, I want to take a file which is 1000 bytes, and truncate
>it to 500 bytes WITHOUT COPYING IT.

Not possible in UNIX System V through SVR3.2, probably supported in SVR4.0.

You can simulate this operation by snarfing the intended ultimate file
contents somewhere safe (like an in-memory array, if it will fit, or
a temp file), then use creat() to truncate the file to 0 length, then
write back the desired final contents.

kucharsk@uts.amdahl.com (William Kucharski) (08/13/89)

In article <708@msa3b.UUCP>, kevin@msa3b.UUCP (Kevin P. Kleinfelter) writes:
> O.K. I give up.  How do you set the size of a file in SYSV.
> In particular, I want to take a file which is 1000 bytes, and truncate
> it to 500 bytes WITHOUT COPYING IT.

What you're looking for is a SYSV version of the BSD (f)truncate(3) call.

If you're lucky enough to be running a version of SVR3 which implements the
undocumented F_FREESP fcntl, the code below should do nicely...

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#ifndef NULL
#define NULL	0
#endif

int
ftruncate(fd, length)
int	fd;	/* file descriptor */
off_t	length;	/* length to set file to */
{
	extern	long	lseek();

	struct	flock	fl;
	struct	stat	filebuf;

	if (fstat(fd, &filebuf) < 0)
		return(-1);

	if (filebuf.st_size < length) {
		/* extend file length */

		if ((lseek(fd, (length - 1), SEEK_SET)) < 0)
			return(-1);	

		/* write a "0" byte */

		if ((write(fd, "", 1)) != 1)
			return(-1);
	} else {
		/* truncate length */

		fl.l_whence = 0;
		fl.l_len = (off_t) 0;
		fl.l_start = length;
		fl.l_type = F_WRLCK;	/* write lock on file space */

		/* 
		 * This relies on the UNDOCUMENTED F_FREESP argument to 
		 * fcntl(2), which truncates the file so that it ends at the
		 * position indicated by fl.l_start.
		 *
		 * If you can't find it listed in your <fcntl.h> or 
		 * <sys/fcntl.h>, chances are it isn't implemented in
		 * your kernel.
		 */

		if (fcntl(fd, F_FREESP, &fl) < 0)
			return(-1);
	}

	return(0);
}


int
truncate(path, length)
char	*path;
off_t	length;
{
	int	fd;	/* file descriptor */

	if ((path == NULL) || (*path == NULL)) {
		errno = EINVAL;
		return(-1);
	}

	if ((fd = open(path, O_WRONLY)) < 0)
		return(-1);

	if (ftruncate(fd, length) < 0) {
		(void) close(fd);
		return(-1);
	}

	(void) close(fd);
	return(0);
}
-- 
					William Kucharski

ARPA: kucharsk@uts.amdahl.com
UUCP: ...!{ames,apple,decwrl,sun,uunet}!amdahl!kucharsk

Disclaimer:  The opinions expressed above are my own, and may not agree with
	     those of any other sentient being, not to mention those of my 
	     employer.  So there.

dougm@queso.ico.isc.com (Doug McCallum) (08/14/89)

In article <10723@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
   In article <708@msa3b.UUCP> kevin@msa3b.UUCP (Kevin P. Kleinfelter) writes:
   >O.K. I give up.  How do you set the size of a file in SYSV.
   >In particular, I want to take a file which is 1000 bytes, and truncate
   >it to 500 bytes WITHOUT COPYING IT.

   Not possible in UNIX System V through SVR3.2, probably supported in SVR4.0.

   You can simulate this operation by snarfing the intended ultimate file
   contents somewhere safe (like an in-memory array, if it will fit, or
   a temp file), then use creat() to truncate the file to 0 length, then
   write back the desired final contents.

While not documented in the fcntl man page or listed in the fcntl man
page with 386/ix, the XENIX compatibility of V.3.2 provides the
"chsize" call in the XENIX compatibility library (-lx) and the
F_CHSIZE fcntl function which are basically "ftruncate".  using
chsize(fd, size) does what ftruncate would do.

#define ftruncate(fd,size) fcntl(fd, F_CHSIZE, size)

will work if you don't want to load the XENIX library.

So, from V.3.2 on there is likely to be something equivalent to
ftruncate.

Doug McCallum
Interactive Systems Corp.
dougm@ico.isc.com

chris@mimsy.UUCP (Chris Torek) (08/15/89)

In article <18lG02Em4aQn01@amdahl.uts.amdahl.com> kucharsk@uts.amdahl.com
(William Kucharski) writes:
>int
>ftruncate(fd, length)
[much deleted]
>	if (filebuf.st_size < length) {
>		/* extend file length */

The 4BSD ftruncate() call will not extend files.  (If it did,
it would probably have been called `fsetsize'; and a function
like this one should probably be so called.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

kucharsk@uts.amdahl.com (William Kucharski) (08/15/89)

In article <19072@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
 >In article <18lG02Em4aQn01@amdahl.uts.amdahl.com> kucharsk@uts.amdahl.com
 >(William Kucharski) writes:
 >>int
 >>ftruncate(fd, length)
 >[much deleted]
 >>	if (filebuf.st_size < length) {
 >>		/* extend file length */
 >
 >The 4BSD ftruncate() call will not extend files.  (If it did,
 >it would probably have been called `fsetsize'; and a function
 >like this one should probably be so called.)

Well, it may not be a good porting guide, but my SunOS 4.0 man page says:

DESCRIPTION
     truncate() causes the file  referred  to  by  path  (or  for
     ftruncate()  the  object  referred  to by fd) to have a size
     equal to length bytes.  If the file  was  previously  longer
     than  length, the extra bytes are removed from the file.  If
     it was shorter, bytes between the old and  new  lengths  are
     read  as  zeroes. [...]

-- 
					William Kucharski

ARPA: kucharsk@uts.amdahl.com
UUCP: ...!{ames,apple,decwrl,sun,uunet}!amdahl!kucharsk

Disclaimer:  The opinions expressed above are my own, and may not agree with
	     those of any other sentient being, not to mention those of my 
	     employer.  So there.