Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lseek with SEEK_CUR unexpectedly generates huge sparse files #9

Open
aklomp opened this issue Aug 10, 2014 · 1 comment
Open

lseek with SEEK_CUR unexpectedly generates huge sparse files #9

aklomp opened this issue Aug 10, 2014 · 1 comment

Comments

@aklomp
Copy link
Collaborator

aklomp commented Aug 10, 2014

Found this while writing testcases. This innocent-looking script will generate a 4.1GB sparse file on my machine:

<?php

// Open a file, write something:
$state = smbclient_state_new();
smbclient_state_init($state, null, 'testuser', 'password');
$file = smbclient_creat($state, 'smb://localhost/testshare/lseektest.txt');
smbclient_write($state, $file, 'abcdefgh');

// Seek 3 characters onwards:
smbclient_lseek($state, $file, 3, SEEK_CUR);

// Write some more, close the file:
smbclient_write($state, $file, 'foo', 3);
smbclient_close($state, $file);
smbclient_state_free($state);

Expected outcome: a file of 14 bytes in size: the characters 'abcdefgh', three zero bytes, and 'foo'.

I tried unsuccessfully to reproduce this behaviour with an equivalent c program, which leads me to conclude that this is a bug in libsmbclient-php somewhere.

#include <string.h>
#include <libsmbclient.h>

static void
smbclient_auth_func (SMBCCTX *ctx, const char *server, const char *share, char *wrkg, int wrkglen, char *user, int userlen, char *pass, int passlen)
{
    strcpy(wrkg, "");
    strcpy(user, "testuser");
    strcpy(pass, "password");
}

int main ()
{
    char *uri = "smb://localhost/testshare/lseektest.txt";
    SMBCCTX *ctx = smbc_new_context();
    smbc_setFunctionAuthDataWithContext(ctx, smbclient_auth_func);
    smbc_init_context(ctx);

    SMBCFILE *file = smbc_getFunctionCreat(ctx)(ctx, uri, 0666);
    smbc_getFunctionWrite(ctx)(ctx, file, "abcdefgh", 8);

    smbc_getFunctionLseek(ctx)(ctx, file, 3, SEEK_CUR);

    smbc_getFunctionWrite(ctx)(ctx, file, "foo", 3);
    smbc_getFunctionClose(ctx)(ctx, file);
    smbc_free_context(ctx, 1);
}

Makefile:

test: test.c
    $(CC) -lsmbclient -I/usr/include/samba-4.0 -o $@ $^

The c program outputs a file 11 bytes in size, containing the string 'abcdefghfoo'. Better, but also not what I expected.

More weirdness: in the PHP version, the lseek call returns '3'. In the c version, the lseek call returns '8'. Neither is correct from the documentation's point of view, since the return value should be the current absolute offset into the file (that is, '11').

@aklomp
Copy link
Collaborator Author

aklomp commented Aug 10, 2014

  • Under the hood, libsmbclient-php translates all three seek types into a SEEK_SET.
  • An strace shows that the PHP code does indeed trigger an fcntl64(11, F_GETLK64, {type=F_UNLCK, whence=SEEK_SET, start=4294967299, len=3, pid=0})
  • This is a casting problem, but it's hard to pinpoint. I think it might have something to do with compiling this module within the PHP framework. For some odd reason, my copy of libsmbclient and my compiler appear to disagree about the type of off_t (which is sorta worrying). However, not when I call the library from my c program.

Compiled within the PHP stack, this line (hand-patched in our libsmbclient.c) gives me the large negative offset:

if ((ret = smbc_lseek(state->ctx, file, 3, (int)whence)) > -1)

But the same line in my c program is fine.

  • Could not reproduce in our Travis CI environment: the integration test that creates a 4.1GB file on my machine apparently gives proper file contents and offset sizes on Travis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant