Approach to File Locking?

This is a discussion on Approach to File Locking? within the Linux Programming forums, part of the Platform Specific Boards category; Hi there, I'm writing a class which can be used to read/write files. I want to implement file locking, and ...

  1. #1
    Registered User
    Join Date
    Sep 2009
    Posts
    5

    Approach to File Locking?

    Hi there,

    I'm writing a class which can be used to read/write files. I want to implement file locking, and wondering how best to achieve it in Linux.

    I understand that to lock files using fcntrl(), I must open them with 'open()', rather than 'fopen()'. However, fopen() implements read/write buffering, whereas open() usually does not.

    As I see it, I have two options:

    1. When the class opens a file, it also created a 'lock file' beside it. Presumably, the main file is opened using fopen(), whereas the lock file is created with open() and then locked. When opening an existing file, my class should therefore check for an existing lock file to determine whether the file can be opened in the required mode. I understand that this is a pretty standard approach.

    Alternatively, I could implement the following approach and was wondering what people think:

    2. Use the open() call to open/create a single main file only (i.e. no extra lock file), and fcntrl() to lock it. However, because read/writes are unlikely to be buffered, I would have to implement my own buffering within the workings of my class.

    Is there any overriding reason why I should go with option 1 over option 2?

    Thanks

  2. #2
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,265
    However, fopen() implements read/write buffering, whereas open() usually does not.
    open() will do buffering as long as you don't pass it the O_DIRECT flag.
    bit∙hub [bit-huhb] n. A source and destination for information.

  3. #3
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,183
    If you implement locking yourself, you will have to make sure checking and creating a lock file is an atomic operation.

    Otherwise nasty things can still happen (if you start 2 instances at the same time, and instance A opens a file, and before A had the chance to create the lock file, instance B also checks, and successfully opens that file...)

  4. #4
    Registered User
    Join Date
    Sep 2009
    Posts
    5
    Hey thanks for response.

    >open() will do buffering as long as you don't pass it the O_DIRECT flag.

    That's interesting. I admit to being a little confused on the issue. There's an interesting discussion on the topic here:

    fopen() vs. open() - C / C++ answers

    A couple of key quotes are:
    "The real issue, apart from portability (open() and friends are actually
    *very* portable, even if the standard doesn't guarantee it), is that,
    on certain platforms, read() and write() are OS primitives and, therefore,
    much more expensive than ordinary library calls. No big deal when used
    with large data chunks, but using read() instead of getc() and write()
    instead of putc() may destroy the program's performance. That's why
    the <stdio.h> I/O routines add one *additional* layer of buffering."
    and

    "Files opened with open() need not even necessarily be buffered,
    regardless of whether they are syscalls -- It depends on the type of
    file, the operating system and many other factors (it could be opened
    with O_SYNC, on a filesystem mounted synchronously, be a terminal are
    other device, or whatever).

    Files opened with fopen(), however, are guaranteed to be buffered. Even
    if they aren't buffered from the start, they can always be made
    buffered."

    OK, assuming open() gives the desired level of buffering, what's the advantage of using a separate lock file?

  5. #5
    Registered User
    Join Date
    Apr 2008
    Posts
    395
    read/write() do buffering (the kernel maintains caches and so on for files) that's why you have to sync() your file systemss before turning off your machine, however it costs you a syscall contrary to fread/fwrite() (which do the syscall periodically). i don't see what bothers you about fopen() over open(), you can still use fcntl() or even flock() while having open your file with fopen(), just get back the fd with fileno().

  6. #6
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    If you want to use FILE objects and your platform supports them, you can use flockfile / funlockfile since they're likely to do the same thing you're trying to implement.

  7. #7
    Registered User
    Join Date
    Sep 2009
    Posts
    5
    >i don't see what bothers you about fopen() over open(), you can still use fcntl() or even flock() while having open your file with fopen(), just get back the fd with fileno().

    Because my past attempts at this failed to work. But I'm starting to realise that, perhaps, it is my understanding of file locking on Linux that is inadequate.

    On Windows, it is possible to exclusively open a file (i.e. preventing other processes from opening it also). It was this I was expecting to achieve on Linux.

    On Linux, however, I'm currently reading that file locking is advisory by default. Meaning, I guess, that if I lock the contents of a file, this will not prevent another process from opening that file in read-write mode. Rather, the process must specifically check for the lock status.

    Is this correct?

    I'm not just trying to get some code working here, rather I'm trying to understand the whole approach to file locking on Linux.

    With advisory locking and the need for cooperating processes, I guess the use of separate locking files makes a little more sense. Any thoughts?

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Hacking Linux Exposed

    Quote Originally Posted by above
    These functions, while managed by the Linux kernel, are known as advisory locking mechanisms. Any program which doesn't bother checking to see if a lock is in place will never know. The kernel won't stop it from reading or writing the file.

    This can be a problem when some programs correctly wait for an exclusive lock on a file, but other programs out of your control access the same files simultaneously without lock checks. If you don't have the code, it may be difficult or impossible to wrap some sort of external locking mechanism around the closed source program.

    In these cases, you can enforce locking at the kernel level with mandatory locks. Mandatory locking is implemented on a file-by-file basis. When a program attempts to lock a file with lockf or fcntl that has mandatory locking set, the kernel will prevent all other programs from accessing the file.[1] Processes which use flock will not trigger a mandatory lock.
    Looks like you have to mount the filesystem with a switch to indicate to the kernel to permit this.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    Registered User
    Join Date
    Apr 2008
    Posts
    395
    that's interesting, i was not aware of the 'mand' mount option. On the other side, there is a relevant file in the Documentation/filesystems folder of the kernel source (mandatory-locking.txt), it looks a bit out of date so i don't know if the problems discussed are still valid. Some other problems are also discussed on the wikipedia 'File locking' page (unlink). As long as the kernel doesn't enforce the mandatory locking policy, it's hard to do anything; but linux is only one unix flavor and it seems others can do it (solaris, hp-ux...).

    and at last this is what posix says:
    For advisory file record locking to be effective, all processes that have access to a file must cooperate and use the advisory mechanism before doing I/O on the file. Enforcement-mode record locking is important when it cannot be assumed that all processes are cooperating. For example, if one user uses an editor to update a file at the same time that a second user executes another process that updates the same file and if only one of the two processes is using advisory locking, the processes are not cooperating. Enforcement-mode record locking would protect against accidental collisions.

    Secondly, advisory record locking requires a process using locking to bracket each I/O operation with lock (or test) and unlock operations. With enforcement-mode file and record locking, a process can lock the file once and unlock when all I/O operations have been completed. Enforcement-mode record locking provides a base that can be enhanced; for example, with sharable locks. That is, the mechanism could be enhanced to allow a process to lock a file so other processes could read it, but none of them could write it.

    Mandatory locks were omitted for several reasons:

    1.

    Mandatory lock setting was done by multiplexing the set-group-ID bit in most implementations; this was confusing, at best.
    2.

    The relationship to file truncation as supported in 4.2 BSD was not well specified.
    3.

    Any publicly readable file could be locked by anyone. Many historical implementations keep the password database in a publicly readable file. A malicious user could thus prohibit logins. Another possibility would be to hold open a long-distance telephone line.
    4.

    Some demand-paged historical implementations offer memory mapped files, and enforcement cannot be done on that type of file.

    Since sleeping on a region is interrupted with any signal, alarm() may be used to provide a timeout facility in applications requiring it. This is useful in deadlock detection. Since implementation of full deadlock detection is not always feasible, the [EDEADLK] error was made optional.

  10. #10
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I can kind of understand why. It is hard to see why a process needs to lock a file. If the process created it, why would it require a lock, since no other process will "guess" the name and start doing crazy things for no reason to a file it has nothing to do with, and if the process has a conflict with itself, that is due to sloppy programming. If it did not create the file, it should not just be allowed to lock bunches of files, even if it is allowed to delete them -- this is bound to be more of a security risk than the opposite, since other processes that use the file will probably be able to deal with one that is missing easier than one which is locked, and you could tie up tons of resources this way. If the process hangs, your lock is stuck there.

    A lot can be done with owner/group permissions. Eg, you can create a new user for the process, but put it in an exising group, and use that to separate read vs write access for self vs. other processes. You can also setuid() getuid() yourself repeatedly.

    Of course, a privileged process can override that, but that is the point. You don't have the freedom to do whatever anywhere with the filesystem and you shouldn't have it, either; you should not be allowed to go so far in making your app bulletproof that you jeopardize the system itself.

    BigAngryDog says this is for what I presume to be a general purpose utility class. So it's a nice thought, but I'll wager no one can actually come up with a real use for this (ie, something that can't be done another way) that isn't irrationally paranoid (ie, protects against imaginary threats).
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 09:39 AM
  2. file processing updating record error
    By uuser in forum C Programming
    Replies: 2
    Last Post: 04-27-2003, 01:13 AM
  3. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 11:12 PM
  4. Hmm....help me take a look at this: File Encryptor
    By heljy in forum C Programming
    Replies: 3
    Last Post: 03-23-2002, 10:57 AM
  5. Need a suggestion on a school project..
    By Screwz Luse in forum C Programming
    Replies: 5
    Last Post: 11-27-2001, 02:58 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21