A multi-threaded remote file system based on TCP sockets with file versioning support.
- WRITE: Upload files to the server
- GET: Download files from the server (with version support)
- RM: Delete remote files
- LS: View file version history
- Multi-threading: Support multiple concurrent client connections
- Version Control: Automatically save file history versions
- Concurrency Control: Use mutex locks to protect shared resources
.
├── protocol.h # Protocol definitions and shared structures
├── utils.c # Utility function implementations
├── rfserver.c # Server main program
├── rfs.c # Client program
├── Makefile # Build configuration
└── test.sh # Automated test script
make # Build all
make server # Build server only
make client # Build client only
make clean # Clean build files./rfserverThe server listens on port 7768 with storage root directory at ./storage.
WRITE - Upload File
./rfs WRITE local/file.txt remote/path/file.txtGET - Download File
./rfs GET remote/file.txt local/downloaded.txt
./rfs GET remote/file.txt:v2 local/version2.txt # Specific versionRM - Delete File
./rfs RM remote/file.txtLS - View Version Information
./rfs LS remote/file.txtSTOP - Stop Server
./rfs STOPstorage/
├── file.txt # Current version
└── .versions/
├── file.txt.v1 # Version 1
├── file.txt.v2 # Version 2
└── file.txt.meta # Metadata
- First write creates version 1
- Subsequent writes save current file as old version, write new content
- Metadata records version numbers, timestamps, and counts
Threading Model
- Main thread: Listen and accept client connections
- Worker threads: Handle each client in separate thread
Mutex Protection
pthread_mutex_t file_mutex; // Protects file operationsProtected operations: file writing, version assignment, metadata updates, file deletion.
chmod +x test.sh
./test.shmake setup
./rfserver &
echo "Hello" > test.txt
./rfs WRITE test.txt remote/test.txt
./rfs GET remote/test.txt downloaded.txt
./rfs LS remote/test.txt
./rfs STOPServer (Machine A)
# Edit protocol.h: set SERVER_IP to Machine A's IP
./rfserverClient (Machine B)
# Edit protocol.h: set SERVER_IP to Machine A's IP
make client
./rfs WRITE local.txt remote.txt- STATUS_FILE_NOT_FOUND (-2): File does not exist
- STATUS_OUT_OF_STORAGE (-3): Insufficient disk space
- STATUS_INVALID_PATH (-4): Invalid path (contains ".." or absolute path)
- STATUS_ERROR (-1): Other errors
Edit protocol.h:
#define SERVER_PORT 7768
#define SERVER_IP "127.0.0.1"
#define BUFFER_SIZE 8192
#define MAX_VERSIONS 100typedef struct {
char command[16]; // Command: WRITE, GET, RM, LS
char arg1[512]; // First argument
char arg2[512]; // Second argument
long file_size; // File size in bytes
int version; // Version (0=latest, >0=specific)
} CommandMessage;
typedef struct {
int status; // Status code
long data_size; // Data size
char message[256]; // Message
} ResponseMessage;Thread Safety
pthread_mutex_lock(&file_mutex);
// Critical section: file operations
pthread_mutex_unlock(&file_mutex);File Transfer
// Client sends
while ((bytes = fread(buffer, 1, BUFFER_SIZE, fp)) > 0) {
send(socket_desc, buffer, bytes, 0);
}
// Server receives
while (remaining > 0) {
bytes = recv(client_sock, buffer, to_read, 0);
fwrite(buffer, 1, bytes, fp);
remaining -= bytes;
}| Question | Requirement | Status |
|---|---|---|
| Q1 | WRITE command | Implemented |
| Q2 | GET command | Implemented |
| Q3 | RM command | Implemented |
| Q4 | Multi-threading | Implemented |
| Q5 | File versioning | Implemented |
| Q6 (Bonus) | LS command | Implemented |
| Q7 (Bonus) | GET version | Implemented |
Server won't start
netstat -tulpn | grep 7768
killall rfserverConnection refused
sudo ufw allow 7768/tcp
ps aux | grep rfserverPermission errors
chmod 755 storageCourse: 93.202 Inter-Process Communication with TCP Sockets in C