ดึงชื่อไฟล์จาก file descriptor ใน C


105

เป็นไปได้ไหมที่จะได้ชื่อไฟล์ของ file descriptor (Linux) ใน C?


ฉันเดาว่าคำตอบที่เลือกควรให้กับ zneak เนื่องจากโซลูชันของเขามีความสามารถในการพกพาที่ดีขึ้นและไม่มีปัญหาการเข้าถึงที่ระบุไว้
Sergei

ไม่รองรับ Ubuntu 14.04 (เคอร์เนล 3.16.0-76-generic) ฉันเดาว่ามันไม่รองรับบน Linux เลย
felipou

สำหรับ MacOS, เห็นนี้คำตอบสำหรับคำถามอื่นโดยD.Nathanael
Jonathan Leffler

คำตอบ:


121

คุณสามารถใช้readlinkใน/proc/self/fd/NNNที่ NNN คืออธิบายไฟล์ สิ่งนี้จะทำให้คุณได้ชื่อไฟล์เหมือนตอนที่เปิดอย่างไรก็ตามหากไฟล์ถูกย้ายหรือลบตั้งแต่นั้นมาไฟล์นั้นอาจไม่ถูกต้องอีกต่อไป (แม้ว่า Linux จะสามารถติดตามการเปลี่ยนชื่อได้ในบางกรณี) เพื่อตรวจสอบstatชื่อไฟล์ที่กำหนดและfstatfd คุณมีและให้แน่ใจว่าst_devและst_inoจะเหมือนกัน

แน่นอนไม่ใช่ตัวอธิบายไฟล์ทั้งหมดที่อ้างถึงไฟล์และสำหรับสิ่งที่คุณจะเห็นสตริงข้อความแปลก ๆ เช่นpipe:[1538488]. เนื่องจากชื่อไฟล์จริงทั้งหมดจะเป็นพา ธ สัมบูรณ์คุณจึงสามารถระบุได้ว่าชื่อไฟล์ใดที่ง่ายพอ นอกจากนี้ตามที่คนอื่น ๆ ตั้งข้อสังเกตไว้ไฟล์สามารถมีฮาร์ดลิงก์หลายตัวชี้ไปที่พวกเขาซึ่งจะรายงานเฉพาะที่เปิดด้วยเท่านั้น หากคุณต้องการค้นหาชื่อทั้งหมดของไฟล์ที่กำหนดคุณจะต้องสำรวจระบบไฟล์ทั้งหมด


9
ตราบเท่าที่ไฟล์ต้นฉบับยังคงมีการอ้างอิงอยู่ (การเปิดfdจะเป็นการอ้างอิงเช่นนั้น) จะไม่สามารถใช้หมายเลขไอโหนดซ้ำได้ ซอฟต์แวร์ใด ๆ ที่ใช้หมายเลขไอโหนดหลังจากปิดไฟล์หรือก่อนที่จะเปิดขึ้นมาจะต้องเป็นไปตามเงื่อนไขการแข่งขัน
R .. GitHub STOP HELPING ICE

3
อันตราย Will Robinson! วิธีนี้ใช้ไม่ได้ผลเสมอไป - หากคุณsetuid()เล่นกลอาจเป็น/proc/self/fdไปได้ที่กระบวนการของคุณจะไม่สามารถเข้าถึงได้ ดู: permalink.gmane.org/gmane.linux.kernel/1302546
David Given

2
@bdonlan: และในกรณี / proc ไม่ได้ติดตั้ง?
user2284570

1
@ user2284570 คำตอบนี้เฉพาะสำหรับ Linux ฉันไม่รู้ว่า NetBSD รองรับ procfs หรือไม่ - หากโฮสต์ที่ใช้ร่วมกันของคุณไม่มีให้อาจเป็นเพราะ NetBSD ไม่รองรับเลยและใช้กลไกอื่นแทน คุณอาจต้องการโพสต์คำถามอื่นโดยเน้น NetBSD เพื่อดูว่ามีใครรู้ว่า NetBSD เปิดเผยข้อมูลนี้อย่างไร (คุณอาจต้องการลองใช้คำตอบของ zneak ด้านล่าง OS X คล้ายกับ BSD มากกว่า Linux)
bdonlan

1
@bdonlan: NetBSD support / proc แต่ไม่บังคับให้ติดตั้ง ทุกครั้งที่ฉันพูดถึงคำตอบคือ "เปลี่ยนไปใช้ผู้ให้บริการที่มีต้นทุนสูงกว่าและคุณจะได้รับ / proc" ดังนั้นฉันกำลังมองหาวิธีแก้ปัญหาที่ไร้ประโยชน์
user2284570

91

ฉันมีปัญหานี้ใน Mac OS X เราไม่มี/procระบบไฟล์เสมือนดังนั้นโซลูชันที่ยอมรับจึงไม่สามารถใช้งานได้

เรามีF_GETPATHคำสั่งสำหรับfcntl:

 F_GETPATH          Get the path of the file descriptor Fildes.  The argu-
                    ment must be a buffer of size MAXPATHLEN or greater.

ดังนั้นในการรับไฟล์ที่เชื่อมโยงกับตัวอธิบายไฟล์คุณสามารถใช้ข้อมูลโค้ดนี้:

#include <sys/syslimits.h>
#include <fcntl.h>

char filePath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filePath) != -1)
{
    // do something with the file path
}

เนื่องจากฉันจำไม่ได้ว่าMAXPATHLENมีการกำหนดไว้ที่ไหนฉันคิดว่าPATH_MAXจาก syslimits น่าจะดี


@uchuugaka ไม่น่าจะใช่ ใช้getsockname.
zneak

2
คุณคาดหวังอะไร? เว้นแต่จะเป็นซ็อกเก็ต UNIX จะไม่มีไฟล์ที่เกี่ยวข้อง
zneak

2
@uchuugaka ใช่ทุกอย่างเป็นไฟล์ แต่ไม่ใช่ทุกอย่างที่เป็นรายการไดเร็กทอรีที่มีชื่อและตำแหน่งภายในโครงสร้างระบบไฟล์ ไฟล์ถูกแสดงโดยไอโหนดซึ่งสามารถอยู่ได้โดยไม่มีรายการไดเร็กทอรีใด ๆ ที่อ้างถึงไฟล์นั้น
lgeorget

9
ใน <sys / param.h>: #define MAXPATHLEN PATH_MAX
geowar

1
ฉันเพิ่งทดสอบสิ่งนี้และยังคงถูกต้องหากไฟล์ถูกย้ายและคุณเรียกอีกครั้ง (หมายถึง: คุณได้รับเส้นทางใหม่ของไฟล์) อย่างไรก็ตามสิ่งนี้ไม่รองรับบน linux (ทดสอบบน Ubuntu 14.04 - ไม่ได้กำหนด F_GETPATH)
felipou


15

ดังที่ไทเลอร์ชี้ให้เห็นว่าไม่มีวิธีใดที่จะทำสิ่งที่คุณต้องการได้ "โดยตรงและเชื่อถือได้" เนื่องจาก FD ที่ระบุอาจตรงกับชื่อไฟล์ 0 (ในหลายกรณี) หรือ> 1 ("ฮาร์ดลิงก์" หลายรายการเป็นวิธีการอธิบายสถานการณ์หลังโดยทั่วไป ). หากคุณยังต้องการฟังก์ชั่นที่มีข้อ จำกัด ทั้งหมด (เกี่ยวกับความเร็วและความเป็นไปได้ที่จะได้ผลลัพธ์ 0, 2, ... แทนที่จะเป็น 1) นี่คือวิธีที่คุณสามารถทำได้: อันดับแรกfstat FD - สิ่งนี้จะบอกคุณ ผลstruct statที่ได้คืออุปกรณ์ที่มีไฟล์อยู่จำนวนฮาร์ดลิงก์ที่มีไม่ว่าจะเป็นไฟล์พิเศษ ฯลฯ สิ่งนี้อาจตอบคำถามของคุณได้อยู่แล้วเช่นถ้า 0 ฮาร์ดลิงก์คุณจะรู้ว่าไม่มีชื่อไฟล์ที่เกี่ยวข้อง บนดิสก์

หากสถิติทำให้คุณมีความหวังคุณจะต้อง "เดินตามต้นไม้" ของไดเรกทอรีบนอุปกรณ์ที่เกี่ยวข้องจนกว่าคุณจะพบฮาร์ดลิงก์ทั้งหมด (หรือแค่อันแรกหากคุณไม่ต้องการมากกว่าหนึ่งอันและอันใดอันหนึ่งจะทำ ). เพื่อจุดประสงค์นั้นคุณใช้readdir (และแน่นอน opendir & c) เปิดไดเร็กทอรีย่อยแบบวนซ้ำจนกว่าคุณจะพบว่าstruct direntได้รับหมายเลขไอโหนดเดียวกันกับที่คุณมีในต้นฉบับstruct stat(ในเวลานั้นหากคุณต้องการเส้นทางทั้งหมดแทนที่จะเป็นเพียงชื่อ คุณจะต้องเดินห่วงโซ่ของไดเรกทอรีย้อนกลับเพื่อสร้างใหม่)

หากวิธีการทั่วไปนี้เป็นที่ยอมรับได้ แต่คุณต้องการรหัส C ที่ละเอียดกว่านี้โปรดแจ้งให้เราทราบมันจะไม่ยากที่จะเขียน (แม้ว่าฉันจะไม่เขียนมันถ้ามันไร้ประโยชน์กล่าวคือคุณไม่สามารถทนต่อประสิทธิภาพที่ช้าอย่างหลีกเลี่ยงไม่ได้หรือ ความเป็นไปได้ในการรับ! = 1 ผลลัพธ์สำหรับวัตถุประสงค์ในการสมัครของคุณ ;-)


9

ก่อนที่จะเขียนสิ่งนี้ออกไปอย่างเป็นไปไม่ได้ฉันขอแนะนำให้คุณดูซอร์สโค้ดของคำสั่งlsof

อาจมีข้อ จำกัด แต่ดูเหมือนว่า lsof จะสามารถกำหนด file descriptor และชื่อไฟล์ได้ ข้อมูลนี้มีอยู่ในระบบไฟล์ / proc ดังนั้นจึงควรได้รับจากโปรแกรมของคุณ


6

คุณสามารถใช้ fstat () เพื่อรับไอโหนดของไฟล์โดย struct stat จากนั้นใช้ readdir () คุณสามารถเปรียบเทียบไอโหนดที่คุณพบกับสิ่งที่มีอยู่ (โครงสร้างไดเรนต์) ในไดเร็กทอรี (สมมติว่าคุณรู้จักไดเร็กทอรีมิฉะนั้นคุณจะต้องค้นหาระบบไฟล์ทั้งหมด) และค้นหาชื่อไฟล์ที่เกี่ยวข้อง น่ารังเกียจ?


1

เป็นไปไม่ได้ ตัวอธิบายไฟล์อาจมีหลายชื่อในระบบไฟล์หรืออาจไม่มีชื่อเลย

แก้ไข: สมมติว่าคุณกำลังพูดถึงระบบ POSIX แบบเก่าโดยไม่มี API เฉพาะระบบปฏิบัติการใด ๆ เนื่องจากคุณไม่ได้ระบุระบบปฏิบัติการ


4
จากนั้นคำตอบของฉันก็ใช้ได้ Linux ไม่มีสิ่งอำนวยความสะดวกในการทำเช่นนี้ ตัวอธิบายไฟล์ Linux (POSIX) ไม่จำเป็นต้องอ้างถึงไฟล์และแม้ว่าจะอ้างถึง inodes ไม่ใช่ชื่อไฟล์ก็ตาม ตัวอธิบายสามารถชี้ไปที่ไฟล์ที่ถูกลบ (ซึ่งจึงไม่มีชื่อนี่เป็นวิธีทั่วไปในการสร้างไฟล์ชั่วคราว) หรืออาจชี้ไปที่ไอโหนดที่มีหลายชื่อ (ฮาร์ดลิงก์)
Tyler McHenry

3
ลองดูซอร์สโค้ด lsof :) นั่นคือสิ่งที่ฉันทำเมื่อมีคำถามเดียวกันนี้กับตัวเองในขณะที่ย้อนกลับไป lsof ทำงานเกี่ยวกับมนต์ดำและแพะบูชายัญ - คุณไม่สามารถหวังว่าจะทำซ้ำพฤติกรรมของมันได้ เพื่อให้เฉพาะเจาะจงมากขึ้น lsof จะทำงานร่วมกับเคอร์เนลลินุกซ์อย่างแน่นหนาและไม่ได้ทำสิ่งที่มันทำโดยใช้ API ใด ๆ ที่มีให้สำหรับโค้ดของผู้ใช้
Tyler McHenry

28
Linux มี proc API แบบไม่พกพาสำหรับสิ่งนี้ มีข้อ จำกัด จริง ๆ แต่การบอกว่ามันเป็นไปไม่ได้นั้นเป็นเพียงเรื่องเท็จ
bdonlan

1
@Tyler - lsof ทำงานใน userspace ดังนั้นจึงมี API สำหรับทุกสิ่งที่มีให้สำหรับรหัสของผู้ใช้ :)
bdonlan

1
@ เป็ดความสามารถในการพกพานั่นอาจเป็นเหตุผลว่าทำไมแหล่งที่มาของ lsof จึงมีมนต์ดำมากมาย ตัวแปร UNIX แต่ละตัวจะแตกต่างกัน อินเทอร์เฟซ linux proc ไม่ได้แย่เกินไปจริงๆ alebit มีเอกสารค่อนข้างเบาบาง
bdonlan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.