改进lockdemo.c文件锁代码:如何阻止文件被追加写入?
fcntl Problem Description
I found a file locking code snippet (
lockdemo.c) online that runs correctly, but it doesn't meet my needs: when the file is locked, I can still append data tolockdemo.c. How can I prevent this behavior?Here's the original code:
/* ** lockdemo.c -- shows off your system's file locking. Rated R. */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { /* l_type l_whence l_start l_len l_pid */ struct flock fl = { F_WRLCK, SEEK_SET, 0, 0, 0 }; int fd; fl.l_pid = getpid(); if (argc > 1) fl.l_type = F_RDLCK; if ((fd = open("lockdemo.c", O_RDWR)) == -1) { perror("open"); exit(1); } printf("Press <RETURN> to try to get lock: "); getchar(); printf("Trying to get lock..."); if (fcntl(fd, F_SETLKW, &fl) == -1) { perror("fcntl"); exit(1); } printf("got lock\n"); printf("Press <RETURN> to release lock: "); getchar(); fl.l_type = F_UNLCK; /* set to unlock same region */ if (fcntl(fd, F_SETLK, &fl) == -1) { perror("fcntl"); exit(1); } printf("Unlocked.\n"); close(fd); }
Why the Original Code Doesn't Block Appends
The fcntl locks you're using are advisory locks—this is the default behavior on Unix-like systems. Advisory locks don't enforce access to the file; they only work if every process that accesses the file voluntarily checks the lock status before performing operations. If a process skips checking the lock and writes directly, the kernel won't stop it.
Your original code locks the entire file (setting l_len = 0 means "lock from l_start to the end of the file, including any future extensions"), but this only blocks other processes that also attempt to acquire a conflicting lock.
Solutions to Block Unlocked Appends
1. Make All Processes Respect the Lock (Recommended)
The most reliable and portable approach is to ensure every process that writes to lockdemo.c first checks for and acquires the appropriate lock before writing.
Here's an example of an append program that follows this rule—if lockdemo holds the lock, this program will wait until the lock is released before writing:
// safe_append.c -- appends to lockdemo.c only when no lock is held #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> int main() { int fd; struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0}; // Open the file for appending if ((fd = open("lockdemo.c", O_WRONLY | O_APPEND)) == -1) { perror("open failed"); exit(EXIT_FAILURE); } // Wait to acquire an exclusive write lock printf("Waiting for lock to append...\n"); if (fcntl(fd, F_SETLKW, &fl) == -1) { perror("failed to acquire lock"); close(fd); exit(EXIT_FAILURE); } // Now safely append data const char* data = "This is a safe append.\n"; if (write(fd, data, sizeof(data)-1) == -1) { perror("write failed"); } // Release the lock fl.l_type = F_UNLCK; if (fcntl(fd, F_SETLK, &fl) == -1) { perror("failed to release lock"); } close(fd); printf("Append successful.\n"); return EXIT_SUCCESS; }
2. Use Mandatory Locking (Alternative, Less Portable)
If you need to block processes that don't check locks voluntarily, you can enable mandatory locking, which forces the kernel to enforce lock rules. However, this has limitations:
- Not all file systems support mandatory locking (e.g., ext4 does, but some network file systems don't).
- It requires specific file system mount options and file permissions.
To set up mandatory locking:
- Remount the file system with the
mandoption (replace/path/to/your/fswith your actual mount point):sudo mount -o remount,mand /path/to/your/fs - Set the setgid bit on
lockdemo.cand remove the group execute permission (this tells the kernel to enforce locks on the file):chmod g+s,g-x lockdemo.c
Once enabled, any process that tries to write to lockdemo.c while it's locked will be blocked by the kernel, even if it doesn't check the lock.
Final Notes
Advisory locking is almost always the better choice—it's more portable, has fewer performance overheads, and avoids edge cases that come with mandatory locking. Only use mandatory locking if you have no control over the other processes writing to the file.
内容的提问来源于stack exchange,提问作者stack12

