Во время работы я запускаю rm mytest.log из командной строки и наблюдаю, что программа не выдает ошибку при следующем вызове WriteString()
Да, это именно то поведение, которое указано. Также файл не был удален. Единственное, что rm
удаляет, - это конкретная запись пути в файловой системе. Один файл может иметь несколько путей, также называемых hardlinks .
Фактический файл удаляется только после закрытия последней ссылки на него, либо по записи файловой системы (ссылка), либо по дескриптору файла (файл, открытый в программе).
Это специфическое поведение файловой модели Unix долгое время использовалось для реализации "неназванной" разделяемой памяти, путем создания и открытия файла в /dev/shm
, а затем удаления записи файловой системы - потому что этот особый способ работы вводит условие гонки, для чувствительных к безопасности приложений были введены новые системные вызовы, которые позволяют создавать анонимные карты памяти, и совсем недавно в Linux даже появилась функция для создания файла в файловой системе без создания записи пути (open
с O_TMPFILE
флагом).
В более поздних версиях Linux вы даже можете заново создавать / создавать записи файловой системы для файлов, последняя из которых уже была удалена с помощью системного вызова linkat
.
Обновление
Вопрос в том, действительно ли вы хотите выдать ошибку, если последняя запись в файловой системе исчезнет? В конце концов, это не плохое состояние, вы можете спокойно писать и читать без проблем, просто имейте в виду, что как только вы закроете последний файловый дескриптор файла, он будет потерян.
Вполне возможно обнаружить, была ли удалена последняя запись файловой системы, и прервать файловые операции, если это так - однако имейте в виду, что такой код может создать свою собственную долю проблем, например, если программа ожидает создания новой запись в файловой системе, когда все правильно записано в файл, используя linkat.
В любом случае, вы можете fstat
-ing файл (file.Stat
в Go) и посмотреть на количество жестких ссылок в файле. Если это число падает до нуля, все записи файловой системы исчезают. На самом деле получить это число немного сложно в Go, это описано здесь Подсчет жестких ссылок на файл в Go
package main
import (
"fmt"
"log"
"os"
"syscall"
"time"
)
func main() {
fmt.Println("Test Operation")
f, err := os.OpenFile("test.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
for {
n, err := f.WriteString("blah\n")
if err != nil {
log.Fatal(err)
}
log.Printf("wrote %d bytes\n", n)
time.Sleep(2 * time.Second)
stat, err := f.Stat()
if err != nil{
log.Fatal(err)
}
if sys := stat.Sys(); sys != nil {
if stat, ok := sys.(*syscall.Stat_t); ok {
nlink := uint64(stat.Nlink)
if 0 == nlink {
log.Printf("All filesystem entries to original file removed, exiting")
break
}
}
}
}
}