मैं फ़ाइल के अनुमतियों, मालिकों, समय और नाम के साथ ls -l
जैसे आउटपुट पैदा करने वाले ls-alike प्रोग्राम लिखने की कोशिश कर रहा हूं। यदि मैं .
(या कुछ भी नहीं) पास करता हूं तो यह अच्छा है, इसलिए यह वर्तमान निर्देशिका के साथ काम करता है। लेकिन अगर मैं किसी अन्य निर्देशिका को वर्तमान में या उसके बाहर perror
पास करता हूं तो यह कहती है कि "फ़ाइलों तक पहुंच नहीं सकता" ।
कृपया, यह पता लगाने में मेरी मदद करें कि lstat
को अन्य डायरियों में फाइलों तक पहुंचने से कौन रोकता है।
मैं gcc और एक टेक्स्ट एडिटर का उपयोग करता हूं, कोई IDE नहीं, gdb का उपयोग करने के लिए सीखना शुरू किया (डिबग करने की कोशिश की, लेकिन ऐसा कुछ नहीं मिला जो मुझे इंगित करता है कि मैं किस तरह के समाधान की तलाश करूंगा)। इसलिए मैंने यहां सभी कोड डालने का फैसला किया है, इसलिए कोई भी इसे चला सकता है। शायद मैं गलत तर्क पास कर दूं, शायद यह किसी तरह का lstat
गलत व्यवहार है, मुझे नहीं पता। मैं वेब पर इसके बारे में कुछ खोजने की कोशिश कर रहा हूं, लेकिन कोई नतीजा नहीं निकला।
यहाँ मैं इस पल के लिए किया है:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h> // open()
#include <unistd.h> // close()
#include <sys/param.h>
#include <string.h>
#include <limits.h> // PATH_MAX
#include <pwd.h> // structure for getpwuid()
#include <grp.h> // structure for getgrgid()
#include <time.h> // ctime()
static void ls(const char *dir);
void get_info(const char *name, int offset);
int get_maxsize(const char *name);
int main(int argc, char ** argv)
{
if (argc == 1)
ls(".");
else
while (--argc > 0)
ls(*++argv);
return 0;
}
static void ls(const char *dir)
{
struct dirent * entry;
DIR *d = opendir(dir);
char pathbuf[PATH_MAX + 1];
int offset = 0;
if (d == 0) {
perror("ls");
return;
}
/* find max file size for better ls-alike output */
while ((entry = readdir(d)) != NULL) {
realpath(entry->d_name, pathbuf);
/* pathbuf OR entry->d_name here: */
if (get_maxsize(entry->d_name) > offset)
offset = get_maxsize(pathbuf);
}
closedir(d);
d = opendir(dir);
while ((entry = readdir(d)) != NULL) {
/* pathbuf OR entry->d_name here: */
realpath(entry->d_name, pathbuf);
get_info(entry->d_name, offset);
}
closedir(d);
}
void get_info(const char *name, int offset)
{
struct stat statbuf;
struct passwd *pwdPtr;
struct group *grpPtr;
int length = 0;
char *time = NULL;
/* skip . and .. dirs */
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
return;
if (lstat(name, &statbuf) == -1) {
fprintf(stderr, "can't access %s\n", name);
perror("get_info");
return;
}
else
switch (statbuf.st_mode & S_IFMT) {
case S_IFREG: printf("-"); break;
case S_IFDIR: printf("d"); break;
case S_IFCHR: printf("c"); break;
case S_IFBLK: printf("b"); break;
case S_IFLNK: printf("l"); break;
case S_IFSOCK: printf("s"); break;
case S_IFIFO: printf("p"); break;
}
/* owner */
if (statbuf.st_mode & S_IREAD) printf("r");
else printf("-");
if (statbuf.st_mode & S_IWRITE) printf("w");
else printf("-");
if (statbuf.st_mode & S_IEXEC) printf("x");
else printf("-");
/* group */
if (statbuf.st_mode & S_IRGRP) printf("r");
else printf("-");
if (statbuf.st_mode & S_IWGRP) printf("w");
else printf("-");
if (statbuf.st_mode & S_IXGRP) printf("x");
else printf("-");
/* other users */
if (statbuf.st_mode & S_IROTH) printf("r");
else printf("-");
if (statbuf.st_mode & S_IWOTH) printf("w");
else printf("-");
if (statbuf.st_mode & S_IXOTH) printf("x");
else printf("-");
/* hard links */
printf(" %2zu", statbuf.st_nlink);
/* owner name */
if ((pwdPtr = getpwuid(statbuf.st_uid)) == NULL) {
perror("getpwuid");
exit(EXIT_FAILURE);
}
else {
printf(" %s", pwdPtr->pw_name);
}
/* gruop name */
if ((grpPtr = getgrgid(statbuf.st_gid)) == NULL) {
perror("getgrgid");
exit(EXIT_FAILURE);
}
else {
printf(" %s", grpPtr->gr_name);
}
/* size in bytes */
/* "C uses an asterisk in the position of the field
width specifier to indicate to printf that it will
find the variable that contains the value of the field
width as an additional parameter."
http://www.eecs.wsu.edu/~cs150/reading/printf.htm */
while(offset != 0)
{
offset /= 10; /* n=n/10 */
++length;
}
printf(" %*d", length, (int)statbuf.st_size);
/* last modifying time */
time = ctime(&statbuf.st_mtime);
time[strlen(time) - 1] = 0;
printf(" %s", time);
/* index */
// ToDo
/* filename */
printf(" %s", name);
printf("\n");
// -,d,c,b,l,s,p
//if ((statbuf.st_mode & S_IFMT) == S_IFREG)
// printf("- %8ld %s\n", statbuf.st_size, name);
}
int get_maxsize(const char *name)
{
struct stat statbuf;
if (lstat(name, &statbuf) == -1) {
fprintf(stderr, "can't access %s\n", name);
perror("get_maxsize");
return -1;
}
return statbuf.st_size;
}
आउटपुट जब यह ठीक काम करता है (केवल वर्तमान निर्देशिका के साथ):
yulian@deb:~/programming/os$ ./readDir .
-rw-rw-rw- 1 yulian yulian 4387 Mon Nov 30 06:31:51 2015 readDir.c
-rw-rw-rw- 1 yulian yulian 282 Sun Nov 29 04:43:03 2015 sometext.txt
-rwxr-xr-x 1 yulian yulian 13792 Sat Nov 28 11:54:09 2015 readDir
drwxr-xr-x 2 yulian yulian 4096 Fri Nov 27 05:26:42 2015 testDir
// there is test dir called `testDir` where it fails
विफल होने पर आउटपुट:
yulian@deb:~/programming/os$ ./readDir testDir/
can't access 2.jpg
get_maxsize: No such file or directory
can't access ETicket_edc7cb12cdc23e6c04a308f34fd31c28.pdf
get_maxsize: No such file or directory
अपडेट: सुझाए गए समाधान के साथ मैंने get_info
में जोड़ा:
....
char *filemane = NULL;
filemane = strrchr(name, '/') + 1;
/* to prevent . and .. from output */
if (strcmp(filemane, ".") == 0 || strcmp(filemane, "..") == 0)
return;
...
/* filename */
printf(" %s", filemane); // and changed the argument here
इसलिए आउटपुट अब फ़ाइल नाम ls -l
के रूप में तैयार करता है, न कि उनके पूर्ण पथ।
2 जवाब
आपको जो याद आ रहा है, वह है dir जिसे आप पाथफ्यूबल वैरिएबल में एक्सप्लोर करना चाहते हैं। बस एलएस के निम्नलिखित कार्यान्वयन का उपयोग करने पर विचार करें
static void ls(const char *dir)
{
struct dirent * entry;
DIR *d = opendir(dir);
char pathbuf[PATH_MAX + 1];
char tmp[PATH_MAX+1];
int offset = 0;
if (d == 0) {
perror("ls");
return;
}
/* find max file size for better ls-alike output */
while ((entry = readdir(d)) != NULL) {
/* pathbuf OR entry->d_name here: */
// realpath(entry->d_name, pathbuf);
snprintf (tmp, PATH_MAX, "%s/%s", dir, entry->d_name);
if (get_maxsize(tmp) > offset)
offset = get_maxsize(tmp);
}
closedir(d);
d = opendir(dir);
while ((entry = readdir(d)) != NULL) {
/* pathbuf OR entry->d_name here: */
// realpath(entry->d_name, pathbuf);
snprintf (tmp, PATH_MAX, "%s/%s", dir, entry->d_name);
get_info(tmp, offset);
}
closedir(d);
}
मुझे लगता है कि आपका कार्यक्रम विफल हो जाता है क्योंकि आप इसे एक पैरामीटर के रूप में एक रिश्तेदार URL देते हैं, और यह बिल्कुल नहीं जानता कि आप कहां हैं। आपको पहले अपने वर्तमान निर्देशिका के लिए getcwd फ़ंक्शन को कॉल करना चाहिए, इसे प्रोग्राम के पैरामीटर के साथ जोड़ दें और इसे बेहतर काम करना चाहिए। या हो सकता है कि पास करने की कोशिश करें। एक पैरामीटर के रूप में .testDir और न केवल testDir / यह निर्दिष्ट करने के लिए कि आप वर्तमान निर्देशिका में स्थित निर्देशिका चाहते हैं।