2011-01-23 12 views
10

मैंने पहले ही realpath() पढ़ा है, लेकिन क्या कोई ऐसा फ़ंक्शन है जिसे मैं आधार निर्देशिका और फ़ाइल नाम पास कर सकता हूं जो मुझे सिम्लिंक को हल किए बिना निम्नलिखित परिणाम देगा या जांच करेगा कि फाइल वास्तव में मौजूद है या नहीं? या मुझे एक संशोधित realpath() का उपयोग करना है?realpath() symlinks को हल किए बिना?

"/var/", "../etc///././/passwd" => "/etc/passwd" 
+3

"/dir/a_random_synlink/../hello" का नतीजा क्या होना चाहिए? याद रखें कि यह "/ dir/hello" जैसा ही नहीं हो सकता है अगर a_random_synlink एक ही निर्देशिका में निर्देशिका को इंगित नहीं करता – BatchyX

+0

@ बैचएक्स: मानक व्यवहार मानता है: 'readlink -v -m'/home/user/linktoslashtmp /../ 'रिटर्न '/ home/user' – thejh

+1

शायद रीडलिंक यह करता है, लेकिन अंतर्निहित ओएस नहीं करता है। एलएस/होम/उपयोगकर्ता/linktoslashtmp/..// – BatchyX

उत्तर

8

यहाँ एक normalize_path है () फ़ंक्शन:

यदि दिया गया पथ सापेक्ष है, तो फ़ंक्शन वर्तमान कार्य निर्देशिका को पूर्ववत करके शुरू होता है।

फिर विशेष.. जैसे पथ घटक, . या खाली घटकों का इलाज किया जाता है, और परिणाम वापस आ जाता है।

.. के लिए, अंतिम घटक हटा दिया जाता है यदि कोई है (/.. बस / वापस करेगा)।
. या खाली घटकों (डबल /) के लिए, यह अभी छोड़ दिया गया है।

फ़ंक्शन खाली पथ वापस नहीं लौटाता है (/ इसके बदले में लौटाया जाता है)।

#define _GNU_SOURCE /* memrchr() */ 

#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <limits.h> 

char * normalize_path(const char * src, size_t src_len) { 

     char * res; 
     size_t res_len; 

     const char * ptr = src; 
     const char * end = &src[src_len]; 
     const char * next; 

     if (src_len == 0 || src[0] != '/') { 

       // relative path 

       char pwd[PATH_MAX]; 
       size_t pwd_len; 

       if (getcwd(pwd, sizeof(pwd)) == NULL) { 
         return NULL; 
       } 

       pwd_len = strlen(pwd); 
       res = malloc(pwd_len + 1 + src_len + 1); 
       memcpy(res, pwd, pwd_len); 
       res_len = pwd_len; 
     } else { 
       res = malloc((src_len > 0 ? src_len : 1) + 1); 
       res_len = 0; 
     } 

     for (ptr = src; ptr < end; ptr=next+1) { 
       size_t len; 
       next = memchr(ptr, '/', end-ptr); 
       if (next == NULL) { 
         next = end; 
       } 
       len = next-ptr; 
       switch(len) { 
       case 2: 
         if (ptr[0] == '.' && ptr[1] == '.') { 
           const char * slash = memrchr(res, '/', res_len); 
           if (slash != NULL) { 
             res_len = slash - res; 
           } 
           continue; 
         } 
         break; 
       case 1: 
         if (ptr[0] == '.') { 
           continue; 

         } 
         break; 
       case 0: 
         continue; 
       } 
       res[res_len++] = '/'; 
       memcpy(&res[res_len], ptr, len); 
       res_len += len; 
     } 

     if (res_len == 0) { 
       res[res_len++] = '/'; 
     } 
     res[res_len] = '\0'; 
     return res; 
} 
+0

+1: ऐसा लगता है कि वर्तमान निर्देशिका के सापेक्ष पथ का मूल्यांकन किया जाता है। कड़ाई से, मुझे लगता है कि प्रश्न की व्याख्या "/ var /' "के सापेक्ष" पथ का मूल्यांकन करें "../ etc ///././ passwd' है, जो आपकी थीम पर एक साधारण भिन्नता है (आप नहीं करते 'getcwd()' के साथ वर्तमान निर्देशिका को स्थापित करने की आवश्यकता है; आप उपयोगकर्ता द्वारा पारित मान का उपयोग करते हैं)। –

+0

धन्यवाद, अच्छा लग रहा है - मैंने एक pwd पैरामीटर को स्वीकार करने के लिए फ़ंक्शन को थोड़ा सा संशोधित किया। – thejh

+1

निश्चित रूप से, मैं आपको अनुमति देता हूं – arnaud576875

1
function normalize_path($path, $pwd = '/') { 
     if (!isset($path[0]) || $path[0] !== '/') { 
       $result = explode('/', getcwd()); 
     } else { 
       $result = array(''); 
     } 
     $parts = explode('/', $path); 
     foreach($parts as $part) { 
      if ($part === '' || $part == '.') { 
        continue; 
      } if ($part == '..') { 
        array_pop($result); 
      } else { 
        $result[] = $part; 
      } 
     } 
     return implode('/', $result); 
} 

(सवाल बार मैं यह लिखा पर पीएचपी टैग किया गया।)

वैसे भी, यहाँ एक regex संस्करण है:

function normalize_path($path, $pwd = '/') { 
     if (!isset($path[0]) || $path[0] !== '/') { 
       $path = "$pwd/$path"; 
     } 
     return preg_replace('~ 
       ^(?P>sdotdot)?(?:(?P>sdot)*/\.\.)* 
       |(?<sdotdot>(?:(?P>sdot)*/(?!\.\.)(?:[^/]+)(?P>sdotdot)?(?P>sdot)*/\.\.)+) 
       |(?<sdot>/\.?(?=/|$))+ 
     ~sx', '', $path); 
} 
+0

हां, इसे किसी भी भाषा के साथ टैग नहीं किया गया था, किसी ने इसे "php" रखा था और मैंने इसे "c" में बदल दिया - उस टैग को भूलने के लिए खेद है। – thejh

+0

@ user576875 @thejh मेरा बुरा (मैंने इसे PHP के रूप में टैग किया)। पहले अपने हाल के प्रश्नों की जांच करनी चाहिए थी। सभी के लिए माफ़ी –

1

मैं उपयोग Hardex के solution:

#include <string.h> 

char * normalizePath(char* pwd, const char * src, char* res) { 
    size_t res_len; 
    size_t src_len = strlen(src); 

    const char * ptr = src; 
    const char * end = &src[src_len]; 
    const char * next; 

    if (src_len == 0 || src[0] != '/') { 
     // relative path 
     size_t pwd_len; 

     pwd_len = strlen(pwd); 
     memcpy(res, pwd, pwd_len); 
     res_len = pwd_len; 
    } else { 
     res_len = 0; 
    } 

    for (ptr = src; ptr < end; ptr=next+1) { 
     size_t len; 
     next = (char*)memchr(ptr, '/', end-ptr); 
     if (next == NULL) { 
      next = end; 
     } 
     len = next-ptr; 
     switch(len) { 
     case 2: 
      if (ptr[0] == '.' && ptr[1] == '.') { 
       const char * slash = (char*)memrchr(res, '/', res_len); 
       if (slash != NULL) { 
        res_len = slash - res; 
       } 
       continue; 
      } 
      break; 
     case 1: 
      if (ptr[0] == '.') { 
       continue; 
      } 
      break; 
     case 0: 
      continue; 
     } 

     if (res_len != 1) 
      res[res_len++] = '/'; 

     memcpy(&res[res_len], ptr, len); 
     res_len += len; 
    } 

    if (res_len == 0) { 
     res[res_len++] = '/'; 
    } 
    res[res_len] = '\0'; 
    return res; 
} 

उदाहरण:

#include <stdio.h> 

int main(){ 
    char path[FILENAME_MAX+1]; 
    printf("\n%s\n",normalizePath((char*)"/usr/share/local/apps",(char*)"./../../../",path)); 
    return 0; 
} 

आउटपुट:

/usr 


नोट:

  1. पहला तर्क निर्देशिका पथ (पूर्ण पथ) रिश्तेदार को जो अन्य रास्तों सामान्यीकृत किया जाएगा। यह आमतौर पर वर्तमान निर्देशिका का पूर्ण पथ है।
  2. दूसरा तर्क सिम्लिंक को हल किए बिना सामान्यीकृत स्ट्रिंग है।
  3. तीसरा तर्क char* है जिसमें सामान्यीकृत पथ रखने के लिए आवश्यक स्मृति/क्षमता होनी चाहिए।
संबंधित मुद्दे