# How Zakirullin Files Enforces Storage Quota Limits Per User

> Learn how Zakirullin Files enforces storage quota limits per user by validating write operations and allowing admin exemptions. Secure your storage effectively.

- Repository: [Artem Zakirullin/files.md](https://github.com/zakirullin/files.md)
- Tags: internals
- Published: 2026-05-21

---

**Zakirullin Files limits user data by validating file write operations against a configurable per-user quota, while allowing administrators to exempt specific user IDs from storage restrictions.**

The zakirullin/files.md repository provides a markdown file server with built-in storage management capabilities. The quota system operates through a three-layer architecture: configuration loading, user-specific exemptions, and runtime write validation.

## Configuring the Default Quota Limit

The storage quota configuration resides in [`server/config/config.go`](https://github.com/zakirullin/files.md/blob/main/server/config/config.go), where the application defines default limits and environment variable overrides.

```go
// server/config/config.go
StorageQuotaKB    int64  `default:"1024" envconfig:"STORAGE_QUOTA_KB"` // 1 MiB
UnlimitedQuotaIDs string `envconfig:"UNLIMITED_QUOTA_IDS"`

```

The `StorageQuotaKB` field defaults to **1024** (1 MiB) but can be customized at startup using the `STORAGE_QUOTA_KB` environment variable. The configuration loads via `config.LoadBotConfig()` during server initialization.

To set a custom quota before starting the server:

```bash
export STORAGE_QUOTA_KB=5120   # 5 MiB per user

go run ./cmd/server

```

## Exempting Users from Quota Restrictions

Administrators can designate specific users as unlimited by populating the `UnlimitedQuotaIDs` environment variable with comma-separated user identifiers.

The exemption logic lives in [`server/fs/quota.go`](https://github.com/zakirullin/files.md/blob/main/server/fs/quota.go):

```go
// server/fs/quota.go
func isUnlimitedQuota(userID int64, unlimitedIDs string) bool { … }

```

When initializing a user's filesystem in [`server/fs/fs.go`](https://github.com/zakirullin/files.md/blob/main/server/fs/fs.go), the `newUserFS` function checks this status and sets `quotaKB` to **0** for unlimited users, effectively disabling storage checks:

```go
// server/fs/fs.go (newUserFS)
quotaKB := config.ServerCfg.StorageQuotaKB
if isUnlimitedQuota(userID, config.ServerCfg.UnlimitedQuotaIDs) {
    quotaKB = 0
}

```

To exempt specific users:

```bash
export UNLIMITED_QUOTA_IDS="1234,5678"
go run ./cmd/server

```

## Runtime Quota Validation During Write Operations

The enforcement mechanism activates during every file write through the `Write` method in [`server/fs/fs.go`](https://github.com/zakirullin/files.md/blob/main/server/fs/fs.go). The system calculates storage consumption lazily using `storageUsed` and caches results in `storageQuotaCache`.

Before committing data, the code invokes `checkQuota` from [`server/fs/quota.go`](https://github.com/zakirullin/files.md/blob/main/server/fs/quota.go):

```go
// server/fs/quota.go
func checkQuota(rootPath string, backend afero.Fs, quotaKB int64, contentSize int64) error {
    if quotaKB <= 0 { return nil }                          // unlimited
    if storageUsed(rootPath, backend)+contentSize > quotaKB*1024 {
        return ErrQuotaExceeded
    }
    return nil
}

```

The `Write` method calculates the size delta (`newSize - oldSize`) and validates against the quota:

```go
// server/fs/fs.go (Write)
newSize := int64(len(content))
if err := checkQuota(fs.rootPath, fs.backend, fs.quotaKB, newSize-oldSize); err != nil {
    return err
}

```

If validation passes, `recordQuotaUsage` updates the cached total. If the quota would be exceeded, the operation aborts immediately with `ErrQuotaExceeded`.

## Handling Quota Exceeded Errors

When applications attempt to write data that breaches the configured limit, the filesystem returns a specific error that can be handled programmatically:

```go
package main

import (
    "fmt"
    "strings"
    "github.com/zakirullin/files.md/server/fs"
)

func main() {
    userFS, err := fs.NewUserFS(1234)
    if err != nil {
        panic(err)
    }

    content := strings.Repeat("x", 2*1024*1024) // 2 MiB
    if err := userFS.Write(fs.DirJournal, "BigNote.md", content); err != nil {
        fmt.Printf("Write failed: %v\n", err) // ErrQuotaExceeded if quota is 1 MiB
    } else {
        fmt.Println("Write succeeded")
    }
}

```

## Summary

- **Configuration**: Default 1 MiB quotas are defined in [`server/config/config.go`](https://github.com/zakirullin/files.md/blob/main/server/config/config.go) and overridable via `STORAGE_QUOTA_KB`.
- **Exemptions**: Specific user IDs listed in `UNLIMITED_QUOTA_IDS` bypass all restrictions through the `isUnlimitedQuota` helper.
- **Enforcement**: The `checkQuota` function in [`server/fs/quota.go`](https://github.com/zakirullin/files.md/blob/main/server/fs/quota.go) validates every write operation against cached storage totals, aborting with `ErrQuotaExceeded` when limits are breached.
- **Delta Calculation**: Quota checks account for file modifications by comparing new content size against existing file size.

## Frequently Asked Questions

### How do I increase the storage quota for all users?

Set the `STORAGE_QUOTA_KB` environment variable to the desired kilobyte limit before starting the server. For example, `export STORAGE_QUOTA_KB=10240` sets a 10 MiB quota per user. The configuration loads at startup via `config.LoadBotConfig()`.

### Can I give specific users unlimited storage while keeping limits for others?

Yes. Add the user IDs to the `UNLIMITED_QUOTA_IDS` environment variable as comma-separated values. The `newUserFS` function in [`server/fs/fs.go`](https://github.com/zakirullin/files.md/blob/main/server/fs/fs.go) sets `quotaKB = 0` for these users, causing `checkQuota` to skip validation entirely.

### What happens when a user exceeds their storage quota?

The `Write` method returns `ErrQuotaExceeded` immediately before writing data to disk. The operation aborts without modifying the filesystem, and the application receives the error to handle appropriately.

### How does the system calculate current storage usage?

The `storageUsed` function calculates consumption by walking the user's root directory, with results cached in `storageQuotaCache` to minimize filesystem traversal during frequent write operations.