Skip to content

Commit

Permalink
Merge pull request #3 from tshinnic/master
Browse files Browse the repository at this point in the history
Update seek() for large file support (>32 bit position values)
  • Loading branch information
baudehlo committed Jun 22, 2011
2 parents 9dc1d02 + 6d3a971 commit 3ac09b0
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 41 deletions.
67 changes: 46 additions & 21 deletions fs-ext.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ static int After(eio_req *req) {

case FS_OP_SEEK:
argc = 2;
argv[1] = Integer::New(req->result);
argv[1] = Number::New(store_data->offset);
break;

default:
Expand All @@ -106,13 +106,13 @@ static int After(eio_req *req) {
static int EIO_Seek(eio_req *req) {
store_data_t* seek_data = static_cast<store_data_t *>(req->data);

off_t i = lseek(seek_data->fd, seek_data->offset, seek_data->oper);
off_t offs = lseek(seek_data->fd, seek_data->offset, seek_data->oper);

if (i == (off_t)-1) {
if (offs == -1) {
req->result = -1;
req->errorno = errno;
} else {
req->result = i;
seek_data->offset = offs;
}

return 0;
Expand Down Expand Up @@ -215,34 +215,59 @@ static Handle<Value> Flock(const Arguments& args) {
}


#ifdef _LARGEFILE_SOURCE
static inline int IsInt64(double x) {
return x == static_cast<double>(static_cast<int64_t>(x));
}
#endif

#ifndef _LARGEFILE_SOURCE
#define ASSERT_OFFSET(a) \
if (!(a)->IsUndefined() && !(a)->IsNull() && !(a)->IsInt32()) { \
return ThrowException(Exception::TypeError(String::New("Not an integer"))); \
}
#define GET_OFFSET(a) ((a)->IsNumber() ? (a)->Int32Value() : -1)
#else
#define ASSERT_OFFSET(a) \
if (!(a)->IsUndefined() && !(a)->IsNull() && !IsInt64((a)->NumberValue())) { \
return ThrowException(Exception::TypeError(String::New("Not an integer"))); \
}
#define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1)
#endif

// fs.seek(fd, position, whence [, callback] )

static Handle<Value> Seek(const Arguments& args) {
HandleScope scope;

if (args.Length() < 3 ||
!args[0]->IsInt32() || !args[1]->IsInt32() || !args[2]->IsInt32())
{
!args[0]->IsInt32() ||
!args[2]->IsInt32()) {
return THROW_BAD_ARGS;
}

int fd = args[0]->Int32Value();
ASSERT_OFFSET(args[1]);
off_t offs = GET_OFFSET(args[1]);
int whence = args[2]->Int32Value();

if ( ! args[3]->IsFunction()) {
off_t offs_result = lseek(fd, offs, whence);
if (offs_result == -1) return ThrowException(ErrnoException(errno));
return scope.Close(Number::New(offs_result));
}

store_data_t* seek_data = new store_data_t();

seek_data->cb = cb_persist(args[3]);
seek_data->fs_op = FS_OP_SEEK;
seek_data->fd = args[0]->Int32Value();
seek_data->oper = args[2]->Int32Value();
seek_data->offset = args[1]->Int32Value();

if (args[3]->IsFunction()) {
seek_data->cb = cb_persist(args[3]);
eio_custom(EIO_Seek, EIO_PRI_DEFAULT, After, seek_data);
ev_ref(EV_DEFAULT_UC);
return Undefined();
} else {
off_t i = lseek(seek_data->fd, seek_data->offset, seek_data->oper);
delete seek_data;
if (i == (off_t)-1) return ThrowException(ErrnoException(errno));
return scope.Close(Integer::New(i));
}
seek_data->fd = fd;
seek_data->offset = offs;
seek_data->oper = whence;

eio_custom(EIO_Seek, EIO_PRI_DEFAULT, After, seek_data);
ev_ref(EV_DEFAULT_UC);
return Undefined();
}

extern "C" void
Expand Down
159 changes: 139 additions & 20 deletions tests/test-fs-seek.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,15 @@ var tmp_dir = "/tmp",

var file_fd,
result,
err;
err,
offset_big;


// Report on test results - - - - - - - - - - - -

// Clean up and report on final success or failure of tests here
process.addListener('exit', function() {
process.addListener('exit', function listen_for_exit(exit_code) {
//if (debug_me) console.log(' exit_code %j', exit_code);

try {
fs.closeSync(file_fd);
Expand All @@ -79,10 +81,16 @@ process.addListener('exit', function() {
remove_file_wo_error(file_path);

console.log('Tests run: %d ok: %d', tests_run, tests_ok);
assert.equal(tests_ok, tests_run, 'One or more subtests failed');

if ( ! exit_code && tests_ok !== tests_run ) {
console.log('One or more subtests failed!');
process.removeListener('exit', listen_for_exit);
process.exit(1);
}
});



// Test helpers - - - - - - - - - - - - - - -

function remove_file_wo_error(file_path) {
Expand Down Expand Up @@ -123,7 +131,7 @@ function expect_value(api_name, err, value_seen, value_expected) {
function expect_errno(api_name, err, value_seen, expected_errno) {
var fault_msg;

if (debug_me) console.log(' expected_errno(err): ' + err );
if (debug_me) console.log(' expected_errno(err): %j', err );

if ( err ) {
if ( err instanceof Error ) {
Expand All @@ -134,9 +142,49 @@ function expect_errno(api_name, err, value_seen, expected_errno) {
}
} else {
fault_msg = api_name + '(): returned wrong error \'' + err + '\'';
console.log(' (We see non-errno error %j', err);
}
} else {
fault_msg = api_name + '(): returned wrong error \'' + err + '\'';
console.log(' (We see non-Error error %j', err);
}
} else {
fault_msg = api_name + '(): expected errno \'' + expected_errno +
'\', but got result ' + value_seen;
}

if ( ! fault_msg ) {
tests_ok++;
if (debug_me) console.log(' FAILED OK: ' + api_name );
} else {
console.log('FAILURE: ' + arguments.callee.name + ': ' + fault_msg);
if (debug_me) console.log(' ARGS: ', util.inspect(arguments));
}
}


function expect_error(api_name, err, value_seen, expected_error) {
var fault_msg;

if (debug_me) console.log(' expected_error(err): %j', err );

if ( err ) {
if ( err instanceof Error ) {
if ( err.code !== undefined ) {
fault_msg = api_name + '(): returned wrong error \'' + err.message +
'\' (expecting ' + expected_error + ')';
} else if ( err.message !== undefined ) {
if ( err.message !== expected_error ) {
fault_msg = api_name + '(): returned wrong error \'' + err + '\'';
console.log(' (We see non-errno error %j', err);
}
} else {
fault_msg = api_name + '(): returned wrong error \'' + err + '\'';
console.log(' (We see non-errno error %j', err);
}
} else {
fault_msg = api_name + '(): returned wrong error \'' + err + '\'';
console.log(' (We see non-Error error %j', err);
}
} else {
fault_msg = api_name + '(): expected errno \'' + expected_errno +
Expand All @@ -153,6 +201,7 @@ function expect_errno(api_name, err, value_seen, expected_errno) {
}



// Setup for testing - - - - - - - - - - - -

// Check whether this version of node.js has these APIs to test
Expand Down Expand Up @@ -224,35 +273,25 @@ constant_names.forEach(function(name){
// fd value is undefined

tests_run++;
result = err = undefined;
try {
err = fs.seekSync(undefined, 0, 0);
result = fs.seekSync(undefined, 0, 0);
} catch (e) {
err = e;
}

if (err) {
if (debug_me) console.log(' err %j', err);
tests_ok++;
} else {
if (debug_me) console.log(' expected error from undefined fd argument');
}
expect_error('seekSync', err, result, 'Bad argument');


// fd value is non-number

tests_run++;
result = err = undefined;
try {
err = fs.seekSync('foo', 0, 0);
result = fs.seekSync('foo', 0, 0);
} catch (e) {
err = e;
}

if (err) {
if (debug_me) console.log(' err %j', err);
tests_ok++;
} else {
if (debug_me) console.log(' expected error from non-numeric fd argument');
}
expect_error('seekSync', err, result, 'Bad argument');


// fd value is negative
Expand Down Expand Up @@ -313,6 +352,18 @@ try {
expect_errno('seekSync', err, result, 'EINVAL');


// offset value is non-integer

tests_run++;
result = err = undefined;
try {
result = fs.seekSync(file_fd, 4.0001, 0);
} catch (e) {
err = e;
}
expect_error('seekSync', err, result, 'Not an integer');


// offset value is "too big" (beyond end of file)
// This unexpectedly 'works' ...

Expand All @@ -326,6 +377,68 @@ try {
expect_value('seekSync', err, result, 98765);


// offset value is "very big" (from below to beyond 32 bits)

tests_run++;
result = err = undefined;
offset_big = 2 * 1024 * 1024 * 1024 - 1;
try {
result = fs.seekSync(file_fd, offset_big, 0);
} catch (e) {
err = e;
}
expect_value('seekSync', err, result, offset_big);


tests_run++;
result = err = undefined;
offset_big = 2 * 1024 * 1024 * 1024;
try {
result = fs.seekSync(file_fd, offset_big, 0);
} catch (e) {
err = e;
}
expect_value('seekSync', err, result, offset_big);


tests_run++;
result = err = undefined;
offset_big = 42 * 1024 * 1024 * 1024;
try {
result = fs.seekSync(file_fd, offset_big, 0);
} catch (e) {
err = e;
}
expect_value('seekSync', err, result, offset_big);


tests_run++;
result = err = undefined;
offset_big = 8 * 1024 * 1024 * 1024 * 1024 - 1;
// Linux is limited to 43 bits for file position values?
try {
result = fs.seekSync(file_fd, offset_big, 0);
} catch (e) {
err = e;
}
expect_value('seekSync', err, result, offset_big);


tests_run++;
result = err = undefined;
offset_big = 16 * 1024 * 1024 * 1024 * 1024;
// Linux is limited to 43 bits for file position values?
//console.log(' offset_big %s %s', offset_big.toString(), offset_big.toString(16) );
try {
result = fs.seekSync(file_fd, offset_big, 0);
//console.log(' result %s %s', result.toString(), result.toString(16) );
} catch (e) {
err = e;
}
expect_errno('seekSync', err, result, 'EINVAL');



// Test valid calls: seekSync - - - - - - - - - -

// SEEK_SET to 0
Expand Down Expand Up @@ -425,6 +538,12 @@ fs.seek(file_fd, 0, 0, function(err, result) {
fs.seek(file_fd, -98765, 0, function(err, result) {
expect_errno('seek', err, result, 'EINVAL');

// offset value is quite large (over 32 bits)
tests_run++;
offset_big = 42 * 1024 * 1024 * 1024;
fs.seek(file_fd, offset_big, 0, function(err, result) {
expect_value('seek', err, result, offset_big);
});
});
});
});
Expand Down

0 comments on commit 3ac09b0

Please sign in to comment.