Exercises — File operations — open, read, write, seek, close
4.2.32 · D4· Coding › Operating Systems › File operations — open, read, write, seek, close
Shuru karne se pehle, ek shared picture. Ek file numbered mailboxes (bytes) ki ek row hai. Offset ek chhota sa arrow hai jo kehta hai "agla read/write yahan se shuru hoga". Byte positions 0 se count hoti hain.

L1 — Recognition
Q1.1
open("notes.txt", O_RDONLY) succeed karta hai. Ek fresh program mein yeh jo sabse chhoti possible value return kar sakta hai woh kya hai, aur 0 kyun nahin?
Recall Solution
KYA: open sabse chhota unused file descriptor return karta hai.
0 kyun nahin: ek normal program mein fds 0, 1, 2 pehle se stdin, stdout, stderr ke liye occupied hain. Toh sabse chhota unused wala 3 hai.
Answer: 3.
Q1.2
read(fd, buf, 512) 0 return karta hai. Kya yeh koi error hai? Iska kya matlab hai?
Recall Solution
Error nahin hai. 0 ka return matlab hai end of file (EOF) — current offset par aur koi bytes nahin hain. Errors -1 return karti hain (errno set hokar). Toh 0 = "cleanly khatam", -1 = "toot gaya".
Q1.3
Tum open("new.txt", O_WRONLY) call karte ho aur file exist nahin karti. open kya return karta hai?
Recall Solution
Yeh ==-1== return karta hai aur errno = ENOENT set karta hai. O_CREAT ke bina, open koi missing file nahin banayega — O_WRONLY sirf yeh describe karta hai ki tum kaise access karna chahte ho, yeh nahin ki use banana hai ya nahin.
L2 — Application
Q2.1
Ek file exactly 20 bytes lambi hai. Tum lseek(fd, -4, SEEK_END) run karte ho. Kaunsa offset milta hai, aur agla read(fd, buf, 4) kaunse byte indices cover karega?
Recall Solution
SEEK_END kya karta hai: yeh compute karta hai.
Offset arrow byte 16 par land karta hai. Phir 4 bytes ka read indices 16, 17, 18, 19 cover karta hai — exactly last four bytes — aur EOF par ruk jaata hai.

Q2.2
Offset 0 se shuru hota hai. Tum read(fd, buf, 10) call karte ho aur woh 10 return karta hai, phir lseek(fd, 5, SEEK_CUR). Naya offset kya hai?
Recall Solution
Step 1: 10 bytes ka read offset ko apne return value se automatically advance karta hai: .
Step 2: SEEK_CUR matlab .
Answer: 15. (Bytes 10,11,12,13,14 skip ho gaye, kabhi read nahin hue.)
Q2.3
lseek(fd, 0, SEEK_CUR) — yeh idiom kis kaam ke liye use hota hai?
Recall Solution
Yeh current offset mein 0 add karta hai, toh yeh kuch change nahin karta lekin current offset return karta hai. Yeh standard trick hai "main abhi kahan hoon?" poochhne ke liye bina move kiye. WHY kaam karta hai: lseek hamesha newpos return karta hai, aur yahan .
L3 — Analysis
Q3.1
Ek 20-byte file. Tum lseek(fd, 25, SEEK_SET) karte ho phir write(fd, "AB", 2). Naya file size kya hai, aur bytes 20–24 mein kya hai?
Recall Solution
Step 1 (seek): SEEK_SET offset directly set karta hai: — yeh current 20-byte end se aage hai. Yeh allowed hai.
Step 2 (write): offset 25 par 2 bytes likhne se 'A' 25 par aur 'B' 26 par aa jaata hai. Naya size = last written index + 1 = .
Gap (bytes 20–24): kabhi nahin likha gaya → kernel unhe implicit zero bytes treat karta hai. Yeh ek sparse file hai — ek "hole" jo \0 ke roop mein read back hota hai aur koi disk blocks occupy nahin karta.

Q3.2
Do processes dono log.txt ko O_WRONLY | O_APPEND ke saath open karte hain aur har ek "concurrently" ek 8-byte line write karta hai. Explain karo offset model use karke ki kyun koi line clobbered nahin hoti.
Recall Solution
WHY normally dangerous: O_APPEND ke bina, har process ka apna offset hota hai. Dono "offset 40 par likho" compute kar sakte hain, toh ek doosre ko overwrite kar deta hai.
WHY O_APPEND fix karta hai: yeh flag har write ko atomically "seek-to-EOF phir write" ek single indivisible kernel step mein karta hai. Process A 40 par seek karta hai, 8 likhta hai (EOF ab 48); process B ka write phir 48 par seek karta hai, 8 likhta hai (EOF ab 56). Kyunki seek+write interrupt nahin ho sakta, do offsets kabhi collide nahin kar sakte → dono lines survive karti hain, back to back.
Q3.3
read(fd, buf, 100) 40 return karta hai. buf ke kaunse slots safe hain use karne ke liye, aur baaki mein kya hai?
Recall Solution
Sirf buf[0] .. buf[39] (pehle 40 bytes, return value) mein real file data hai. Slots buf[40] .. buf[99] untouched hain — wahi puraana garbage hai jo pehle tha. Toh tumhe n (=40) use karna chahiye, kabhi count (=100) nahin. 100 likhne par 60 bytes junk leak ho jaata.
L4 — Synthesis
Q4.1
Ek robust loop likho jo poora count-byte buffer likhta hai, short writes ko sahi tarike se handle karte hue. Phir: agar count = 4096 aur har write call 1500 return karta hai, toh kitne write calls chalte hain?
Recall Solution
ssize_t total = 0, n;
while (total < count) {
n = write(fd, buf + total, count - total);
if (n < 0) break; // real error → bail
total += n; // advance past bytes already written
}WHY loop: ek single write request se kam transfer kar sakta hai (disk pressure, signals). Production code kabhi assume nahin karta ki ek call kaam khatam kar dega.
Calls ki count 4096 bytes ke liye, 1500 per call:
- Call 1: 1500 likhta hai → total 1500 (remaining 2596)
- Call 2: 1500 likhta hai → total 3000 (remaining 1096)
- Call 3: 1096 maangta hai; short write caps at... lekin sirf 1096 bache hain, toh 1096 likhta hai → total 4096, loop khatam.
Answer: 3 calls.
Q4.2
Pseudo-C mein ek copy_first_k(src, dst, k) design karo jo src ke pehle k bytes ek naye file dst mein copy kare, sab kuch close karte hue. Us case ko handle karo jahan src mein k bytes se kam hain.
Recall Solution
int in = open(src, O_RDONLY);
if (in < 0) return -1; // src missing → -1
int out = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644);// create/empty dst
if (out < 0) { close(in); return -1; }
char buf[4096];
size_t remaining = k;
while (remaining > 0) {
size_t want = remaining < sizeof buf ? remaining : sizeof buf;
ssize_t n = read(in, buf, want);
if (n <= 0) break; // n==0 EOF (src shorter than k) → stop; n<0 error
ssize_t w = 0;
while (w < n) { // robust write of exactly the bytes we read
ssize_t m = write(out, buf + w, n - w);
if (m < 0) { close(in); close(out); return -1; }
w += m;
}
remaining -= n;
}
close(in); close(out);
return 0;KEY design points: read ke return n par loop karo (k par nahin); n == 0 (EOF) par cleanly ruko jab src chhota ho; short-write loop nest karo; O_TRUNC koi bhi purana dst khali karta hai; dono fds close karo.
L5 — Mastery
Q5.1
Tumhara long-running server har request par open/read/close karta hai, lekin ek bug close skip karta hai jab request error karti hai. ulimit -n 1024 hai, aur 1 in 8 requests error karti hai. Roughly kitni requests ke baad agla open fail hone lagta hai, aur kaunsi error ke saath?
Recall Solution
KYA scarce hai: per-process file-descriptor table ka hard cap hai (ulimit -n = 1024). Teen fds (0,1,2) pre-occupied hain, 1024 - 3 = 1021 usable slots bachte hain.
WHY leaks accumulate hote hain: har errored request exactly ek fd leak karta hai (kabhi return nahin hota). Leaks per request .
KAB toot-ta hai: yeh tab fail karta hai jab 1021 free slots sab leak ho jaate hain:
8168th request ke aaspaas agla open ==-1== return karta hai errno = EMFILE ke saath ("too many open files"). Fix: har path par close karo, error paths including.
Q5.2
Ek file 20 bytes ki hai. Is sequence ke baad exact offset predict karo:
lseek(fd, 8, SEEK_SET) → read(fd, buf, 5) (5 return karta hai) → lseek(fd, -3, SEEK_CUR) →
lseek(fd, 0, SEEK_END). Har step ke baad offset do.
Recall Solution
Arrow ko step by step track karo:
SEEK_SET 8→ offset .read 5(5 return karta hai) → offset advance hota hai: .SEEK_CUR -3→ .SEEK_END 0→ .
Offsets: 8 → 13 → 10 → 20. Final answer 20 (EOF).
Q5.3
Sirf offset + reference-count model use karke explain karo ki int fd2 = dup(fd); ke baad lseek(fd2, 0, SEEK_SET) call karna fd par reads ko bhi affect karta hai, jabki ek hi file ko do alag open calls se kholna offset share nahin karta. (Conceptual — koi numbers nahin.)
Recall Solution
dup: descriptor copy karta hai, toh fd aur fd2 same open file description ko point karte hain — same offset arrow. Ise fd2 ke through move karo aur fd bhi woh move dekhta hai (ek arrow, do naam).
Do opens: har open ek alag open file description allocate karta hai, har ek ka apna offset arrow. Ek ko move karne se doosra untouched rehta hai.
Reference count: description sirf tab free hoti hai jab iske saare fds close ho jaate hain; count isliye hai ki ek stray dup'd fd file ko "alive" rakhta hai jab tak har copy close na ho jaaye.
Recall Feynman recap
Is page ka har question actually yeh hai "arrow kahan hai, aur kitne claim-tickets ise point kar rahe hain?" read/write arrow ko apne return value se forward dhakelte hain; lseek ise simple arithmetic se teleport karta hai (SET=absolute, CUR=relative, END=size se); close ek ticket waapis deta hai aur sirf tab saaf karta hai jab last ticket chali jaaye.
Related: File descriptor table · System calls and the kernel boundary · ulimit and resource limits · Buffered I/O (fopen/fread) · File system & inodes · Pipes and sockets.