Skip to content

Commit

Permalink
Attempt to work around lseek SEEK_HOLE bug
Browse files Browse the repository at this point in the history
  • Loading branch information
jmroot committed Oct 7, 2024
1 parent 7354c0d commit af49e24
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/pextlib1.0/Pextlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,54 @@ int ClonefileCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl
return TCL_ERROR;
}

static int fileIsSparseCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
#ifdef SEEK_HOLE
const char *path;
struct stat st;
int fd;
off_t end_offset;
off_t hole_offset;

if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "filename");
return TCL_ERROR;
}

path = Tcl_GetString(objv[1]);
if (-1 == lstat(path, &st)) {
/* an error occurred */
Tcl_SetErrno(errno);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "lstat(", path, "):", (char *)Tcl_PosixError(interp), NULL);
return TCL_ERROR;
}
if (!S_ISREG(st.st_mode)) {
/* not a regular file, haven't seen directories which are sparse yet */
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(false));
return TCL_OK;
}
if ((fd = open(path, O_RDONLY)) < 0) {
Tcl_SetErrno(errno);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "open(", path, "): ", (char *)Tcl_PosixError(interp), NULL);
return TCL_ERROR;
}

lseek(fd, 0, SEEK_SET);
hole_offset = lseek(fd, 0, SEEK_HOLE);
end_offset = lseek(fd, 0, SEEK_END);
close(fd);
if (hole_offset >= 0 && end_offset >= 0
&& hole_offset < end_offset) {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(true));
return TCL_OK;
}
#endif /* SEEK_HOLE */

Tcl_SetObjResult(interp, Tcl_NewBooleanObj(false));
return TCL_OK;
}

int Pextlib_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, "8.4", 0) == NULL)
Expand Down Expand Up @@ -1184,6 +1232,7 @@ int Pextlib_Init(Tcl_Interp *interp)
#ifdef __MACH__
Tcl_CreateObjCommand(interp, "fileIsBinary", fileIsBinaryCmd, NULL, NULL);
#endif
Tcl_CreateObjCommand(interp, "fileIsSparse", fileIsSparseCmd, NULL, NULL);

Tcl_CreateObjCommand(interp, "readline", ReadlineCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "rl_history", RLHistoryCmd, NULL, NULL);
Expand Down
17 changes: 17 additions & 0 deletions src/port1.0/portdestroot.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,23 @@ proc portdestroot::destroot_finish {args} {
ui_warn "[format [msgcat::mc "%s installs files outside the common directory structure."] $subport]"
}

# Work around apparent filesystem bug.
# https://trac.macports.org/ticket/67336
if {[fs_clone_capable $destroot]} {
global workpath
ui_debug "Applying sparse file lseek bug workaround"
fs-traverse -depth fullpath [list $destroot] {
if {[file type $fullpath] eq "file" && [fileIsSparse $fullpath]} {
ui_debug "Cloning $fullpath for workaround"
clonefile $fullpath ${workpath}/.macports-sparse-workaround
file delete ${workpath}/.macports-sparse-workaround
if {![fileIsSparse $fullpath]} {
ui_debug "$fullpath is no longer sparse"
}
}
}
}

# Restore umask
umask $oldmask

Expand Down

0 comments on commit af49e24

Please sign in to comment.