How File Upload and Batch Operations Work in CasaOS: A Technical Deep Dive
CasaOS handles large files through chunked uploads stored in temporary .tmp files and executes bulk file operations asynchronously via a worker queue system.
CasaOS, an open-source personal cloud platform developed by IceWhaleTech, provides enterprise-grade file management through its Go-based backend architecture. Understanding how file upload and batch operations work in CasaOS reveals a sophisticated design that separates HTTP request handling from filesystem I/O. This implementation ensures the UI remains responsive while processing multi-gigabyte transfers and bulk modifications.
Chunked File Upload Architecture
The chunked upload system enables reliable transfer of large files by breaking them into manageable segments. This approach prevents memory exhaustion and supports resumable uploads through an in-memory state tracking mechanism.
Upload Endpoint and Metadata Handling
The upload process begins at POST /v2/file, handled by the PostUploadFile function in route/v2/file.go. The client sends a multipart form containing chunk metadata including chunkNumber, chunkSize, totalChunks, totalSize, identifier, and relativePath. This metadata allows the server to reconstruct the file in the correct order regardless of arrival sequence.
Temporary File Assembly
The FileUploadService.UploadFile method in service/file_upload.go manages the actual file construction. The service maintains an in-memory map (sync.Map) called uploadStatus to track chunk progress without database overhead. For each chunk received:
- The system opens a temporary file with the
.tmpextension - Uses
os.OpenFilewithSeekto position the write cursor at(chunkNumber-1) × chunkSize - Copies the incoming bytes using
io.Copy - Updates the
FileInfostatus in thesync.Map, markinguploaded[chunkNumber-1] = true
When uploadedChunkNum equals totalChunks, the service closes the temporary file, renames it to the final filename (removing the .tmp extension), and removes the entry from the upload map. This ensures partially uploaded files never appear as complete in the filesystem.
Chunk Verification Endpoint
Clients can verify which chunks exist using GET /v2/file/check via the CheckUploadChunk handler. The endpoint returns 204 No Content if the chunk is missing, or 200 OK if present, enabling resumable upload implementations in the UI.
Batch File Operations Architecture
CasaOS implements batch operations through a producer-consumer pattern that queues file operations for asynchronous execution.
Queue and Worker Pattern
The batch API endpoint POST /v1/batch/task in route/v1/file.go triggers the PostOperateFileOrDir handler. This handler validates the request against the model.FileOperate struct, checking for empty item lists, identical source/destination paths, and mounted volume restrictions. Upon validation:
- A UUID is generated for the operation
- The
FileOperateobject is stored inservice.FileQueue(async.Map) - The ID is appended to
service.OpStrArr - If the queue was empty, two goroutines spawn:
ExecOpFilefor execution andCheckFileStatusfor progress monitoring
Operation Execution Flow
The ExecOpFile function in service/file.go processes queued operations sequentially. For each FileOperate item, it iterates through source paths and performs:
- Copy operations: Uses
file.CopyDirto duplicate directory structures - Move operations: Combines
file.CopyDir,os.RemoveAll, andfile.MoveFileto relocate items - Overwrite handling: Respects the
styleparameter (e.g., "overwrite") when destinations exist
The HTTP layer returns immediately with a success response, while these background workers handle the actual filesystem I/O.
Progress Tracking and Notifications
The CheckFileStatus goroutine polls every 3 seconds, calculating completion by comparing ProcessedSize against destination sizes using file.GetFileOrDirSize. When operations complete, the Notify service emits WebSocket broadcasts via SendFileOperateNotify, providing real-time updates to connected clients without requiring polling.
Implementation Examples
Uploading Files via Chunked Transfer
Upload large files by splitting them into chunks and posting to the /v2/file endpoint:
# Example: Uploading a 10MB file in 5MB chunks
FILE=/path/to/large.bin
SIZE=$(stat -c%s "$FILE")
CHUNK=5242880 # 5 MiB
TOTAL=$(( (SIZE + CHUNK - 1) / CHUNK ))
IDENT=upload-$(uuidgen)
for ((i=1; i<=TOTAL; i++)); do
curl -X POST http://localhost:80/v2/file \
-F "path=/data" \
-F "chunkNumber=$i" \
-F "chunkSize=$CHUNK" \
-F "currentChunkSize=$(dd if=$FILE bs=$CHUNK skip=$((i-1)) count=1 2>/dev/null | wc -c)" \
-F "totalChunks=$TOTAL" \
-F "totalSize=$SIZE" \
-F "identifier=$IDENT" \
-F "relativePath=large.bin" \
-F "filename=large.bin" \
-F "file=@<(dd if=$FILE bs=$CHUNK skip=$((i-1)) count=1 2>/dev/null)"
done
The PostUploadFile handler receives each segment and writes it to <path>/<relativePath>.tmp, assembling the final file once all chunks arrive.
Executing Batch Copy or Move Operations
Queue bulk operations using the /v1/batch/task endpoint with a JSON payload matching the model.FileOperate structure:
curl -X POST http://localhost:80/v1/batch/task \
-H "Content-Type: application/json" \
-d '{
"type": "move",
"style": "overwrite",
"to": "/data/destination",
"item": [
{ "from": "/data/source1.txt" },
{ "from": "/data/source2.txt" }
]
}'
This returns immediately while ExecOpFile processes the queue in the background. Monitor progress through the WebSocket channel at /ws or by observing the ProcessedSize field in subsequent status checks.
Batch Deletion Requests
Delete multiple paths simultaneously via DELETE /v1/batch:
curl -X DELETE http://localhost:80/v1/batch \
-H "Content-Type: application/json" \
-d '["/data/old1.txt","/data/old2.txt"]'
The DeleteFile handler validates paths against mounted volumes before executing os.RemoveAll on each target.
Key Source Files and Components
Understanding the CasaOS file upload and batch operations implementation requires familiarity with these specific files:
service/file_upload.go: ContainsUploadFileandTestChunkmethods managing the chunked upload state machine and temporary file assemblyroute/v2/file.go: HTTP handlersPostUploadFileandCheckUploadChunkfor the upload API surfaceroute/v1/file.go: ImplementsPostOperateFileOrDirandDeleteFilefor batch operation endpointsservice/file.go: Houses theFileQueue(sync.Map),ExecOpFileworker, andCheckFileStatusmonitoring logicmodel/file_operate.go: Defines theFileOperatestruct specifying operation types, source items, and destination paths
Summary
- Chunked uploads in CasaOS use temporary
.tmpfiles and in-memorysync.Maptracking to assemble large files without blocking the HTTP layer - The batch operations API (
/v1/batch) implements a non-blocking queue system wherePostOperateFileOrDirenqueues tasks and background goroutines execute them - File upload service (
service/file_upload.go) handles chunk positioning viaSeekandio.Copy, verifying completion whenuploadedChunkNumequalstotalChunks - Worker processes (
ExecOpFileandCheckFileStatus) run asynchronously, updating progress every 3 seconds and emitting WebSocket notifications upon completion - All paths are validated against mounted volumes before deletion or batch operations to prevent system damage
Frequently Asked Questions
How does CasaOS handle interrupted uploads?
CasaOS stores upload progress in an in-memory sync.Map within FileUploadService. If an upload interrupts, the temporary .tmp file persists on disk while the client can query CheckUploadChunk to identify missing chunks. Resuming the upload involves sending only the missing segments, which the UploadFile method writes to the correct offset using Seek before finalizing the file when all chunks arrive.
What is the maximum file size supported for uploads?
The chunked upload architecture theoretically supports files of any size limited only by available disk space and filesystem constraints (such as ext4's 16TB limit or btrfs limits). Since CasaOS streams chunks to disk using io.Copy rather than buffering in memory, individual chunk size and total file size depend on the chunkSize parameter sent by the client, typically configured in the UI settings.
Can batch operations be cancelled once queued?
Once a batch operation enters the service.FileQueue and processing begins via ExecOpFile, the system does not expose a cancellation endpoint in the current implementation. The operation runs to completion unless the CasaOS process restarts, which clears the in-memory queue. Clients should verify operation parameters before submitting to PostOperateFileOrDir.
Why does the batch API return immediately instead of waiting for completion?
The PostOperateFileOrDir handler returns immediately to prevent HTTP timeouts during long-running file operations like copying large directories or moving between different storage devices. This asynchronous design, implemented in route/v1/file.go, allows the UI to remain responsive while background workers in service/file.go handle the actual filesystem I/O and report progress via WebSocket notifications.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →