[net.unix-wizards] truncating a file opened via open

hua@cmu-cs-edu1.ARPA (Ernest Hua) (06/07/85)

___________________________________________________________________________

Does anyone have any idea how to truncate a file at the current point in
writing if it is opened by open()?  I cannot use creat() because the file
is being used by another process, and I cannot use unlink() it is likely
that it is linked.  If the updated contents is longer than the original,
it is not a problem because the file length is just extended.  But if the
updated contents is shorter, the file does not shrink.  We have 4.1BSD on
several 780's and 750's.

Any help would be greatly appreciated.

ARPA:   (see below)
UUCP:   seismo!hua@cmu-cs-gandalf.arpa
CSNET:  hua%cmu-cs-gandalf.csnet@csnet.arpa
___________________________________________________________________________

Live long and prosper.
Keebler { hua@cmu-cs-gandalf.arpa }

ken@turtlevax.UUCP (Ken Turkowski) (06/11/85)

In article <340@cmu-cs-edu1.ARPA> hua@cmu-cs-edu1.ARPA (Ernest Hua) writes:
>Does anyone have any idea how to truncate a file at the current point in
>writing if it is opened by open()?  I cannot use creat() because the file
>is being used by another process, and I cannot use unlink() it is likely
>that it is linked.  If the updated contents is longer than the original,
>it is not a problem because the file length is just extended.  But if the
>updated contents is shorter, the file does not shrink.  We have 4.1BSD on
>several 780's and 750's.

try

size = lseek(fd, 0L, 1);	/* tell(fd) */
ftruncate(fd, size);		/* int fd, size; */

It's yet another undocumented feature on 4.2.
-- 

Ken Turkowski @ CADLINC, Menlo Park, CA
UUCP: {amd,decwrl,hplabs,nsc,seismo,spar}!turtlevax!ken
ARPA: turtlevax!ken@DECWRL.ARPA

steven@luke.UUCP (Steven List) (06/13/85)

In article <786@turtlevax.UUCP> ken@turtlevax.UUCP (Ken Turkowski) writes:
>In article <340@cmu-cs-edu1.ARPA> hua@cmu-cs-edu1.ARPA (Ernest Hua) writes:
>>Does anyone have any idea how to truncate a file at the current point in
>>writing if it is opened by open()?
>
>size = lseek(fd, 0L, 1);	/* tell(fd) */
>ftruncate(fd, size);		/* int fd, size; */
>
>It's yet another undocumented feature on 4.2.

OK, how about System III?  That's my problem.  Someone out there posted
a program that uses ftruncate, and we don't have it.  Solutions are
welcome!
-- 
***
*  Steven List @ Benetics Corporation  *  (415) 940-6300
*  {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
***

guy@sun.uucp (Guy Harris) (06/17/85)

> In article <786@turtlevax.UUCP> ken@turtlevax.UUCP (Ken Turkowski) writes:
> >In article <340@cmu-cs-edu1.ARPA> hua@cmu-cs-edu1.ARPA (Ernest Hua) writes:
> >>Does anyone have any idea how to truncate a file at the current point in
> >>writing if it is opened by open()?
> >
> >size = lseek(fd, 0L, 1);	/* tell(fd) */
> >ftruncate(fd, size);		/* int fd, size; */
> >
> >It's yet another undocumented feature on 4.2.

Undocumented?  Hardly.  See TRUNCATE(2) in the UNIX Programmer's Manual.

> OK, how about System III?  That's my problem.  Someone out there posted
> a program that uses ftruncate, and we don't have it.  Solutions are
> welcome!

There are precisely two solutions for non-4.2BSD systems:

1) implement (f)truncate on your system.  Any implementation on a non-4.2BSD
version of UNIX will probably move to any other non-4.2BSD version with
little difficulty.

2) Copy the entire file, up to the point of truncation, to a temporary file,
then copy it back to the original file.

The "f77" support library uses solution 2), except under 4.2BSD where it
uses solution 1); I believe "truncate" was introduced for the benefit of
"f77".

A comparision of solutions 1) and 2) may indicate why the Berkeley people
added "truncate".  Solution 2) is slow and ugly.

	Guy Harris

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (06/18/85)

UNIX System III/V do not have any way to truncate a file.
The best kludge is to recopy the whole file up to the point of
truncation (yuck).

campbell@maynard.UUCP (Larry Campbell) (06/19/85)

> > >In article <340@cmu-cs-edu1.ARPA> hua@cmu-cs-edu1.ARPA (Ernest Hua) writes:
> > >>Does anyone have any idea how to truncate a file at the current point in
> > >>writing if it is opened by open()?
> 
> There are precisely two solutions for non-4.2BSD systems:
> 1) implement (f)truncate on your system...

Kind of tough for people without source licenses (I know, I'm whining).

> 2) Copy the entire file, up to the point of truncation, to a temporary file,
> then copy it back to the original file.
>
> 	Guy Harris

I don't see how this works unless you unlink the file and then re-creat
it before writing it back.  But the original question implied you only had
a descriptor for the file, not a name...  so you can't unlink or re-creat
it.  And even if you knew the name, other links wouldn't get truncated.
Sounds like it's pretty tough to fake this one ...  sigh ...

- Larry Campbell
  The Boston Software Works, Inc., 120 Fulton St., Boston MA 02109
UUCP: {decvax, security, linus, mit-eddie}!genrad!enmasse!maynard!campbell
ARPA: decvax!genrad!enmasse!maynard!campbell@DECWRL.ARPA

guy@sun.uucp (Guy Harris) (06/20/85)

> > There are precisely two solutions for non-4.2BSD systems:
> > 1) implement (f)truncate on your system...
> 
> Kind of tough for people without source licenses (I know, I'm whining).

Actually, it was meant as a hint to various vendors, some of whom may be
long-distance carriers...

> > 2) Copy the entire file, up to the point of truncation, to a temporary
> > file, then copy it back to the original file.

> I don't see how this works unless you unlink the file and then re-creat
> it before writing it back.

Why unlink it?  Re-"creat"ing will do the job - it truncates the file to
zero length (unless you don't have write permission, which is unlikely
unless the file is newly created and you created it without giving yourself
write permission).

	Guy Harris

smk@axiom.UUCP (Steven M. Kramer) (06/22/85)

I wrote a few routines for non-4.2 machines that mimicked the 4.2
routines.  Ftruncate was one of them.  I probably missed some wierd
conditions (like file descriptors refering to non-reg files, ..., and
errno's), but my ftruncate works OK in a pinch.  I posted the
source to net.sources.
-- 
	--steve kramer
	{allegra,genrad,ihnp4,utzoo,philabs,uw-beaver}!linus!axiom!smk	(UUCP)
	linus!axiom!smk@mitre-bedford					(MIL)

mts@ms.UUCP (Martin Stanley) (06/24/85)

> > > >In article <340@cmu-cs-edu1.ARPA> hua@cmu-cs-edu1.ARPA (Ernest Hua) writes:
> > > >>Does anyone have any idea how to truncate a file at the current point in
> > > >>writing if it is opened by open()?
> > 
> > There are precisely two solutions for non-4.2BSD systems:
> > 1) implement (f)truncate on your system...
> 
> Kind of tough for people without source licenses (I know, I'm whining).
> 
> > 2) Copy the entire file, up to the point of truncation, to a temporary file,
> > then copy it back to the original file.
> >
> > 	Guy Harris
> 
> I don't see how this works unless you unlink the file and then re-creat
> it before writing it back.  But the original question implied you only had
> a descriptor for the file, not a name...  so you can't unlink or re-creat
> it.  And even if you knew the name, other links wouldn't get truncated.
> Sounds like it's pretty tough to fake this one ...  sigh ...
> 
> - Larry Campbell
>   The Boston Software Works, Inc., 120 Fulton St., Boston MA 02109
> UUCP: {decvax, security, linus, mit-eddie}!genrad!enmasse!maynard!campbell
> ARPA: decvax!genrad!enmasse!maynard!campbell@DECWRL.ARPA

There's also another problem: 

	In order to properly simulate the ftruncate() call from 4.2 BSD, 
you must leave the file open in the same mode it was originally opened in.
In order to copy, link, etc. the file you need to fclose() it so you
will need to reopen it later. The catch is that you do not know in what
mode it was originally opened.  (Also, if the file was originally opened
in write-only mode you will not be able to read it to copy it to the
temporary, so you must fclose() the file to begin with and then
re-open for read/write). 

	I wrote a substitute ftruncate() call that takes two arguments:
the file pointer and the file name. (Instead of a file pointer and the
length desired). It truncates the file at the position of the current
file pointer. After the copy and/or re-linking, I reopen the file in
"a+" mode and hope for the best. I do not take care of multiple links
at all, since that was not necessary for my application.

	(If anyone wants my code, drop me a line and I'll send it along.
It works, but certainly can be made more efficient).
-- 

 Martin Stanley
 Department of Computer Science
 University of Toronto
 Toronto, ON
 M5S 1A4

 USENET:	{decvax,ihnp4,linus,uw-beaver}!utcsri!utai!ms!mts
 CSNET:		mts@toronto
 ARPANET:	mts.toronto@csnet-relay

guy@sun.uucp (Guy Harris) (06/27/85)

> 	In order to properly simulate the ftruncate() call from 4.2 BSD, 
> you must leave the file open in the same mode it was originally opened in.
> In order to copy, link, etc. the file you need to fclose() it...

Huh?  You only have to "fclose" it if you don't have enough file descriptors
or if, as you mention, the FD wasn't open for reading and writing.

I also don't understand why so much is made of links.  You don't have to
unlink the file unless you don't have write permission on it; if you have
write permission, a "creat" will do the truncation to zero length quite
well.  (If you have to do the "unlink" and don't have write permission on
the containing directory, you're out of luck.)

All this is slightly beside the point, as the guy wasn't asking for an
"ftruncate()" routine for non-4.2BSD systems, he was just asking for a way
to truncate a file to a particular length.  In some cases (such as in the
F77 support library, which is where both the two-copy scheme and, I believe,
the motivation of "(f)truncate" came from) you know what mode the file was
opened in.

Furthermore, given how slow "ftruncate" are, it's probably best to rewrite
the code to use some other technique, if possible, rather than to simulate
"ftruncate" by brute force.

Then again, since "ftruncate" is useful and can't be nicely built out of
other operations (it can be built out of other operations but the result is
not pretty), it should probably become a part of standard UNIX.  (Remember
V6, the UNIX that stored the seek pointer for a file in the kernel and
didn't let a program get the value, no matter now politely it asked?  "tell"
was added to V6, and the V7 "lseek" returned the seek pointer, so that you
didn't have to use a kludge like counting all the characters you wrote -
which also didn't always work, since you didn't necessarily know where the
seek pointer was then the program started.)

	Guy Harris