Function to truncate a file

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Function to truncate a file

Paul K-2
I'd like to come back to Daurnimator's suggestion to add a file
truncation function to Lua
(http://lua-users.org/lists/lua-l/2011-12/msg00111.html).

I know Luiz responded "truncating to zero length is the same as
opening for writing, except for dates", but it's beneficial in many
cases to write to the same file, as it preserves its attributes,
metadata, permissions, etc.

Paul.

Reply | Threaded
Open this post in threaded view
|

Re: Function to truncate a file

William Ahern
On Wed, Sep 26, 2018 at 05:25:39PM -0700, Paul K wrote:

> I'd like to come back to Daurnimator's suggestion to add a file
> truncation function to Lua
> (http://lua-users.org/lists/lua-l/2011-12/msg00111.html).
>
> I know Luiz responded "truncating to zero length is the same as
> opening for writing, except for dates", but it's beneficial in many
> cases to write to the same file, as it preserves its attributes,
> metadata, permissions, etc.
>
> Paul.

At least on macOS there's no difference between truncate+0 and fopen:

                  inode           atime           mtime           ctime  
  creat           8597642368      20:39:57        20:39:57        20:39:57
  truncate        8597642368      20:39:57        20:39:59        20:39:59
  fopen           8597642368      20:39:57        20:40:01        20:40:01

Perhaps truncate behaves differently on different POSIX systems or Windows
chsize behaves differently than POSIX truncate. But in either case there's
no consistency so it's not something you can depend on. Perhaps Luiz was
mistaken or being intentionally vague because he knew there was some
difference but wouldn't remember

FWIW, here's my test code using Lua 5.3:

  local unix = require"unix"
 
  local function stat_and_print(path, test)
  local st = assert(unix.stat(path))
  print(test,
     st.ino,
     os.date("%H:%M:%S", st.atime // 1),
     os.date("%H:%M:%S", st.mtime // 1),
     os.date("%H:%M:%S", st.ctime // 1))
  end
 
  -- basically the same as fopen(path, "w")
  local function creat(path, mode)
  local oflag = unix.O_CREAT | unix.O_TRUNC | unix.O_WRONLY
  local fd, why, errno = unix.open(path, oflag, mode)
  if not fd then return false, why, errno end
  unix.close(fd)
  return true
  end
 
  local path = os.tmpname()
  print("        ", "inode     ", "atime   ", "mtime   ", "ctime   ")
 
  do
  assert(creat(path, tonumber("666", 8)))
  stat_and_print(path, "creat   ")
  end
 
  unix.sleep(2)
 
  do
  assert(unix.truncate(path))
  stat_and_print(path, "truncate")
  end
 
  unix.sleep(2)
 
  do
  local fh = assert(io.open(path, "w"))
  stat_and_print(path, "fopen   ")
  fh:close()
  end
 
  assert(os.remove(path))

Reply | Threaded
Open this post in threaded view
|

Re: Function to truncate a file

Luiz Henrique de Figueiredo
> At least on macOS there's no difference between truncate+0 and fopen:
> Perhaps Luiz was mistaken or being intentionally vague

I think I meant that io.open(path, "w") might potentially imply in
removing the file and creating a new one.

OTOH, the man page for fopen in both macOS and Linux say

      w      Truncate file to zero length or create text file for writing.

That's exactly what the C99 standard says too.