Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Noitidart/f05ffde7dcaffe792a4d to your computer and use it in GitHub Desktop.
Save Noitidart/f05ffde7dcaffe792a4d to your computer and use it in GitHub Desktop.
_ff-addon-snippet-LibC_fcntl - Working on getting fcntl to work to detect if profile is locked. (js-ctypes)
Cu.import('resource://gre/modules/ctypes.jsm');
Cu.import('resource://gre/modules/osfile.jsm');
function doit() {
if (OS.Constants.Sys.Name == 'Darwin') {
var _libc = ctypes.open('libc.dylib');
} else if (OS.Constants.Sys.Name == 'Linux') {
var _libc = ctypes.open('libc.so.6');
}
var lockFilePath = OS.Path.join(OS.Constants.Path.profileDir, '.parentlock');
var lockFilePath = '/Users/noi/Library/Application Support/Firefox/Profiles/6myop6y5.Unnamed Profile 1/.parentlock';
var lockFilePath = '/home/noi/.mozilla/firefox/b51cfon3.Unnamed Profile 1/.parentlock'; //up1
//var lockFilePath = '/home/noi/.mozilla/firefox/eb0nz6yr.Unnamed Profile 2/.parentlock'; //up2
//var lockFilePath = '/home/noi/.mozilla/firefox/qydytdfk.default/.parentlock'; //main
//var lockFilePath = '/home/noi/.mozilla/firefox/q0rlb7ap.Unnamed Profile 1/.parentlock'; //dev
console.log(lockFilePath);
///////////////fcntl
if (OS.Constants.Sys.Name == 'Darwin') {
var F_GETLK = 7;
var F_RDLCK = 1;
var F_WRLCK = 3;
var F_UNLCK = 2;
/* https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fcntl.2.html
* struct flock {
* off_t l_start; // starting offset
* off_t l_len; // len = 0 means until end of file
* pid_t l_pid; // lock owner
* short l_type; // lock type: read/write, etc.
* short l_whence; // type of l_start
* };
*/
//order matters:
// http://chat.stackexchange.com/transcript/message/17822233#17822233
// https://ask.mozilla.org/question/1134/order-of-strcuture-matters-test-case-flock-for-use-by-fcntl/
var flock = new ctypes.StructType('flock', [
{'l_start': ctypes.unsigned_long},
{'l_len': ctypes.unsigned_long},
{'l_pid': ctypes.int},
{'l_type': ctypes.unsigned_short},
{'l_whence': ctypes.unsigned_short}
]);
} else if (OS.Constants.Sys.Name == 'Linux') {
var F_GETLK = 5;
var F_RDLCK = 0;
var F_WRLCK = 1;
var F_UNLCK = 2;
/* http://linux.die.net/man/2/fcntl
* typedef struct flock {
* ...
* short l_type; //Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
* short l_whence; //How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END
* off_t l_start; //Starting offset for lock
* off_t l_len; //Number of bytes to lock
* pid_t l_pid; //PID of process blocking our lock (F_GETLK only)
* ...
* };
*/
//order matters:
// http://chat.stackexchange.com/transcript/message/17822233#17822233
// https://ask.mozilla.org/question/1134/order-of-strcuture-matters-test-case-flock-for-use-by-fcntl/
var flock = new ctypes.StructType('flock', [
{'l_type': ctypes.unsigned_short},
{'l_whence': ctypes.unsigned_short},
{'l_start': ctypes.unsigned_long},
{'l_len': ctypes.unsigned_long},
{'l_pid': ctypes.int}
]);
}
//int fcntl(int fd, int cmd, ... /* arg */ );
/*
* int fcntl(int fd, int cmd);
* int fcntl(int fd, int cmd, long arg);
* int fcntl(int fd, int cmd, struct flock *lock);
*/
var fcntl = _libc.declare('fcntl',
ctypes.default_abi,
ctypes.int,
ctypes.int,
ctypes.int,
flock.ptr
);
//int open(const char *pathname, int flags, mode_t mode);
//https://github.com/downthemall/downthemall-mirror/blob/c8fd56c464b2af6b8dc7ddee1f9bbe6e9f6e8382/modules/manager/worker_posix.js#L35
var openFd = _libc.declare(
"open",
ctypes.default_abi,
ctypes.int, // retval
ctypes.char.ptr, // path
ctypes.int // flags
);
var closeFd = _libc.declare(
"close",
ctypes.default_abi,
ctypes.int, // retval
ctypes.int // fd
);
var filepath = lockFilePath;
//filepath = OS.Path.join(OS.Constants.Path.desktopDir, 'new.txt');
let fd = openFd(filepath, OS.Constants.libc.O_RDWR); //setting this to O_RDWR fixes errno of 9 on fcntl
if (fd == -1) {
//if file does not exist and O_CREAT was not set. errno is == 2
//if file is a dangling symbolic link. errno is == 2
console.error('failed to open file, fd:', fd, 'errno:', ctypes.errno);
return -1;
} else {
console.log('successfully opened, fd:', fd)
}
try {
var testlock = new flock();
testlock.l_type = F_WRLCK; //can use F_RDLCK but keep openFd at O_RDWR, it just works
testlock.l_start = 0;
testlock.l_whence = OS.Constants.libc.SEEK_SET;
testlock.l_len = 0;
var rez = fcntl(fd, F_GETLK, testlock.address());
console.log('rez:', rez);
if (rez != -1) {
//check testlock.l_type
console.log('testlock:', uneval(testlock));
if (testlock.l_type == F_UNLCK) {
//can also test if testlock.l_pid is not 0
console.info('file is NOT locked');
} else if (testlock.l_type == F_WRLCK) {
console.info('file is WRITE LOCKED, it may be read locked too');
} else if (testlock.l_type == F_RDLCK) {
console.info('file is NOT write locked but just READ LOCKED'); //we know this because testlock tested for write lock first
} else {
console.error('testlock.l_type is unknown, l_type:', testlock.l_type);
}
} else {
console.log('rez was -1, errno', ctypes.errno);
}
} finally {
var rez = closeFd(fd);
if (rez == 0) {
//console.log('succesfully closed, rez:', rez);
} else {
console.error('FAILED to close, rez:', rez, 'errno', ctypes.errno);
}
}
}
console.time('flock');
doit();
console.timeEnd('flock');
@yajd
Copy link

yajd commented Sep 24, 2014

for mac, i had to set l_pid to ctpyes.int otherwies it would throw ctypes.errno == 22 which is EINVAL weidr.

Cu.import('resource://gre/modules/ctypes.jsm');
Cu.import('resource://gre/modules/osfile.jsm');

function doit() {
    var _libc = ctypes.open('libc.dylib');


    //var lockFilePath = OS.Path.join(OS.Constants.Path.profileDir, '.parentlock');
    var lockFilePath = '/Users/noi/Library/Application Support/Firefox/Profiles/6myop6y5.Unnamed Profile 1/.parentlock';
    //var lockFilePath = '/home/noi/.mozilla/firefox/b51cfon3.Unnamed Profile 1/.parentlock'; //up1
    //var lockFilePath = '/home/noi/.mozilla/firefox/eb0nz6yr.Unnamed Profile 2/.parentlock'; //up2
    //var lockFilePath = '/home/noi/.mozilla/firefox/qydytdfk.default/.parentlock'; //main
    //var lockFilePath = '/home/noi/.mozilla/firefox/q0rlb7ap.Unnamed Profile 1/.parentlock'; //dev
    console.log(lockFilePath);

    ///////////////fcntl

    /*
     * typedef struct flock {
     * ...
     * short l_type;     //Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
     * short l_whence;   //How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END
     * off_t l_start;    //Starting offset for lock
     * off_t l_len;      //Number of bytes to lock
     * pid_t l_pid;      //PID of process blocking our lock (F_GETLK only) 
     * ...
     * };
     */
    //https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fcntl.2.html
    //order matters for mac i guess: http://chat.stackexchange.com/transcript/message/17822233#17822233
    var flock = new ctypes.StructType('flock', [
        {'l_start': ctypes.unsigned_long},
        {'l_len': ctypes.unsigned_long},
        {'l_pid': ctypes.int},
        {'l_type': ctypes.unsigned_short},
        {'l_whence': ctypes.unsigned_short}
    ]);


    //int fcntl(int fd, int cmd, ... /* arg */ );
    /*
     * int fcntl(int fd, int cmd);
     * int fcntl(int fd, int cmd, long arg);
     * int fcntl(int fd, int cmd, struct flock *lock);
     */
    var fcntl = _libc.declare('fcntl',
        ctypes.default_abi,
        ctypes.int,
        ctypes.int,
        ctypes.int,
        flock.ptr
    );

    //int open(const char *pathname, int flags, mode_t mode);
    //https://github.com/downthemall/downthemall-mirror/blob/c8fd56c464b2af6b8dc7ddee1f9bbe6e9f6e8382/modules/manager/worker_posix.js#L35
    var openFd = _libc.declare(
        "open",
        ctypes.default_abi,
        ctypes.int, // retval
        ctypes.char.ptr, // path
        ctypes.int // flags
    );

    var closeFd = _libc.declare(
        "close",
        ctypes.default_abi,
        ctypes.int, // retval
        ctypes.int // fd
    );

    var F_GETLK = 7;
    var F_RDLCK = 1;
    var F_WRLCK = 3;
    var F_UNLCK = 2;
    var SEEK_SET = 0;
    var SEEK_CUR = 1;
    var SEEK_END = 2;

    var filepath = lockFilePath;
    //filepath = OS.Path.join(OS.Constants.Path.desktopDir, 'new.txt');
    var fd = openFd(filepath, OS.Constants.libc.O_RDWR); //setting this to O_RDWR fixes errno of 9 on fcntl
    if (fd == -1) {
        //if file does not exist and O_CREAT was not set. errno is == 2
        //if file is a dangling symbolic link. errno is == 2
        console.error('failed to open file, fd:', fd, 'errno:', ctypes.errno);
        return -1;
    } else {
        console.log('successfully opened, fd:', fd)
    }
    try {
        var testlock = new flock();
        testlock.l_type    = F_WRLCK; //can use F_RDLCK but keep openFd at O_RDWR, it just works
        testlock.l_start   = 0;
        testlock.l_whence  = SEEK_SET;
        testlock.l_len     = 0;

        ctypes.errno = 0;
        console.log('errno:', ctypes.errno);
        var rez = fcntl(fd, F_GETLK, testlock.address());
        console.log('rez:', rez);
        if (rez != -1) {
            //check testlock.l_type
            console.log('testlock:', uneval(testlock));
            if (testlock.l_type == F_UNLCK) {
                //can also test if testlock.l_pid is not 0
                console.info('file is NOT locked');
            } else if (testlock.l_type == F_WRLCK) {
                console.info('file is WRITE LOCKED, it may be read locked too');
            } else if (testlock.l_type == F_RDLCK) {
                console.info('file is NOT write locked but just READ LOCKED'); //we know this because testlock tested for write lock first
            } else {
                console.error('testlock.l_type is unknown, l_type:', testlock.l_type);
            }
        } else {
            console.log('rez was -1, errno', ctypes.errno);
        }
    } finally {
        var rez = closeFd(fd);
        if (rez == 0) {
            //console.log('succesfully closed, rez:', rez);
        } else {
            console.error('FAILED to close, rez:', rez, 'errno', ctypes.errno);
        }
    }

}

console.time('flock');
doit();
console.timeEnd('flock');

@Noitidart
Copy link
Author

When using the libc constants follow this commentary to figure out field order:

noida   btw guys if short is 2 what is off_t and pid_t?
11:27   noida   8?
11:27       *** avikpal quit (Ping timeout: 121 seconds)
11:27   jdm noida: http://stackoverflow.com/questions/9073667/where-to-find-the-complete-definition-of-off-t-type
11:29   noida   so they say blkcnt_t and off_t shall be signed integer types.
11:35   noida   jdm in ctypes to get size of platform dependent signed integer do you go ctypes.size_t.size?

11:37   noida   ah so maybe harshil__ is on 64bit system thats why he's getting these numbers:
11:37   noida   FLOCK_L_LEN:16 L_TYPE:0 L_PID:24 L_WHENCE:2 L_START: 8
11:37   jdm noida: yep, makes sense
11:37   harshil__   yes my os is 64bit
11:37   noida   super this is awesome!
11:38   noida   so to find offset of field in structure i take that number and divide by size of the type?
11:39   jdm noida: no, you multiply the offset in bytes by *
11:39   jdm er, by 8
11:39   jdm actually I'm not sure what you
11:39   jdm you're asking
11:39       *** Fallen|away is now known as Fallen
11:39   noida   these offsets are supposed to help me figure out how to create teh structure
11:40   noida   for example in mac flock structure is this:https://gist.github.com/Noitidart/f05ffde7dcaffe792a4d#file-_ff-addon-snippet-fcntl-js-L40
11:40   jdm ah
11:40   noida   and in ubuntu the flock structure has the same fields but in different order: see line 67 of that
11:41   jdm so the offset of a field will show how many bytes should have preceded it
11:41   noida   oh!!
11:42   jdm if you sort them in ascending order, that's the field order
11:42   jdm and then you sort out the types that will take up that many bytes
11:42   noida   ohhh!!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment