문제

나는 내 사용자가 실수로 내 애플리케이션의 데이터 디렉토리에 들어가는 것을 방지하는 방법을 한동안 조사해 왔습니다.

내 응용 프로그램은 폴더를 사용하여 구조화된 프로젝트를 저장합니다.폴더 내부 구조는 비판적이므로 엉망으로 만들어서는 안됩니다.사용자가 이 폴더를 전체적으로 볼 수 있지만 열 수는 없도록 하고 싶습니다(예: Mac 번들).

Windows에서 그렇게 할 수 있는 방법이 있나요?

현재 답변에서 편집

물론 사용자가 자신의 데이터에 액세스하는 것을 방지하려는 것이 아니라 실수로 데이터 무결성을 파괴하지 못하도록 보호하는 것뿐입니다.따라서 암호화나 비밀번호 보호가 필요하지 않습니다.

.Net 답변에 감사드립니다. 하지만 안타깝게도 이는 주로 .Net 프레임워크에 대한 종속성이 없는 C++ 프로젝트입니다.

내가 언급하는 데이터는 빛이 아니며 전자현미경에서 얻은 이미지입니다.이러한 데이터는 매우 클 수 있으므로(~100MiB~~1GiB) 모든 것을 메모리에 로드하는 것은 옵션이 아닙니다.이는 거대한 이미지이므로 스토리지는 전체 아카이브를 메모리에 로드하지 않고 한 번에 하나의 파일에 액세스하여 점진적으로 데이터를 읽을 수 있는 방법을 제공해야 합니다.

게다가 이 응용 프로그램은 우리가 책임지지 않는 일부 구성 요소가 포함된 레거시 제품입니다.현재 IO 코드를 유지할 수 있는 솔루션이 더 좋습니다.

Shell Extension이 흥미로워 보입니다. 솔루션을 더 자세히 조사해 보겠습니다.

LarryF, Filter Driver나 DefineDOSDevice에 대해 자세히 설명해주실 수 있나요?나는 이러한 개념에 익숙하지 않습니다.

도움이 되었습니까?

해결책 9

일부 같네요 퓨즈의 창 포트 나타나기 시작합니다. 레거시 코드를 그대로 유지할 수 있기 때문에 이것이 최상의 솔루션이라고 생각합니다.

다른 팁

당신이 할 수있는 몇 가지 일이 있습니다.

한 가지는 중요 폴더에 대한 사용자 정의보기를 생성하는 폴더 뷰 Windows Shell 확장자를 만들 수 있다는 것입니다. 사용자 정의 폴더 뷰를 만들면 폴더를 한 줄의 텍스트 "Nothing To Bee Here"로 비어 있거나 동일한 방법을 사용하는 GAC Viewer와 같은 더 많은 합병증을 만들 수 있습니다. 이 방법은 상당히 복잡하지만이 복잡성은 다음과 같은 것을 사용하여 완화 할 수 있습니다. 이 CodeProject 기사의 도서관으로서.

또 다른 솔루션은 가상 파일 시스템을 Zip하는 것입니다. 따라서 System.io를 직접 사용하여 다른 것을 사용하는 모든 코드를 교체해야합니다. ASP.NET 2.0은이 정확한 이유로이 작업을 수행했으며 그 이유를 쉽게 만들 수 있습니다. MSDN 기사 VirtualPathProvider를 구현합니다.

구조적 저장 설명하는 시나리오를 위해 설계되었습니다.

구조화 된 스토리지는 단일 파일을 Storages 및 스트림으로 알려진 구조화 된 객체 모음으로 처리하여 COM의 파일 및 데이터 지속성을 제공합니다.

"스토리지"는 폴더와 유사하며 "스트림"은 파일과 유사합니다. 기본적으로 구조화 된 스토리지 API를 사용하여 액세스 할 때 작동하고 완전한 자체 포함 된 파일 시스템처럼 보이는 단일 파일이 있습니다.

그러나 다음과 같이하십시오.

COM 기술에 대한 확실한 이해는 구조화 된 스토리지의 발달 사용에 대한 전제 조건입니다.

프로그램 내부 또는 외부?

방법이 있지만 쉽지 않습니다. 파일 시스템에서 필터 드라이버를보고있을 것입니다.

zip 파일을 Aproach를 가져 가면 (내가 당신을 고려했지만 언급하지 않은) Deflate 알고리즘을 사용하는 것이 좋습니다. 그러나 자신의 파일 시스템을 사용하는 것이 좋습니다 ... TAR 형식과 같은 것을보십시오. 그런 다음 코드를 작성하여 디스크에 작성 될 때 팽창/디플레이트 알고리즘을 지나서 모든 I/O를 전달하십시오. Zip "Format"을 사용하지 않을 것입니다. 파일을 너무 쉽게 살펴보고 PK를 처음 두 바이트로 찾아 파일을 압축 해제합니다 ....

나는 Joshperry의 제안을 가장 좋아합니다.

물론 모든 데이터를 단일 파일 내에 저장하는 장치 드라이버를 작성할 수도 있지만 다시 드라이버를보고 있습니다. (드라이버 밖에서 구현할 수 있다고 확신 할 수는 없습니다. 아마도 당신은 아마도 당신의 프로그램 호출 내에서 정의 된 것으로 정의되어 코드에만 액세스 할 수있는 이름을 제공하며, 일반 파일 시스템으로 간주됩니다. ). 나는 몇 가지 아이디어를 가지고 놀고, 그들이 작동한다면, 나는 당신에게 샘플을 촬영할 것입니다. 이제 당신은 내가 관심을 갖게되었습니다.

프로젝트 디렉토리를 .zip 파일로 래핑하고 데이터를 사용하는 것처럼 데이터를 저장할 수 있습니다. 두 번 클릭에 즉각적인 영향을 미치지 않도록 비표준 연장을 만듭니다. ;-)

물론 이것은 프로그램이 구축되는 방식에 따라 대신 .zip을 사용하기 위해 모든 파일 IO를 랩핑해야한다는 것을 의미합니다. 이것은 지루할 수 있습니다. 이미 Java를 위해 이루어졌습니다. Truezip. 어쩌면 당신은 그것을 영감으로 사용할 수 있습니까?

유혹을받은 경우 - 폴더 권한을 부르는 것을 권장하지 않을 것입니다. 명백한 이유는 도움이되지 않습니다.

분리 된 스토리지를 사용할 수 있습니다.

http://www.ondotnet.com/pub/a/dotnet/2003/04/21/isolatedstorage.html

모든 문제를 해결하지는 않지만 앱 데이터를 손상에서 잘 사용하지 못합니다.

명심하십시오 : 파일 시스템에 저장하면 사용자는 항상 볼 수 있습니다. Explorer를 조작하고 대신 CMD.exe를 사용합니다. 또는 총 사령관. 또는 다른 것.

사람들이 파일을 엉망으로 만들고 싶지 않다면 추천합니다.

  • 파일의 변조를 방지하기 위해 암호화합니다
  • 아카이브 (즉, zip)에 넣고 암호를 보호 한 다음 런타임에 압축/압축을 압축 할 수 있습니다 (아카이브를 빠르게 수정하는 알고리즘을 찾을 것입니다).

물론 완전히 보호는 아니지만 구현하기가 직접적으로 진행되며 운영 체제 내부에 펑키 한 물건을 설치할 필요는 없으며 가장 호기심 많은 사용자를 멀리해야합니다.

물론 컴퓨터 자체를 제어하지 않고 사용자 컴퓨터에서 파일을 완전히 제어 할 수는 없습니다.

Tomalak의 zip 아카이브 제안을 '프로젝트 파일'로 사용한 소프트웨어(Visual Paradigm의 ​​Agilian)를 본 적이 있습니다.Zip 파일은 잘 이해되며 비표준 파일 확장자를 사용하면 일반 사용자가 '파일'을 조작하는 것을 방지할 수 있습니다.이것의 가장 큰 장점 중 하나는 손상이 발생한 경우 표준 도구를 사용하여 문제를 해결할 수 있으며 기본 응용 프로그램을 지원하기 위한 특수 도구를 만드는 것에 대해 걱정할 필요가 없다는 것입니다.

C ++ 에서이 일을하고 있다는 소식을 듣고 기쁩니다. 아무도 C ++를 더 이상 "필요한"것으로 보지 않는 것 같습니다. 그것은 모두 c#이, 그리고 asp.net은 ... 심지어 내가 맹세 할 때 나는 모든 C# 집에서 일한다. 절대 C ++가 내가해야 할 모든 일을하고 일부는 스위치를하고 일부는 일부를 수행합니다. 나는 내 자신의 기억을 정리하기에 충분히 성인입니다! heh .. 어쨌든, 문제로 돌아가 ...

그만큼 DefineDOSDevice() 드라이브 문자, 포트 이름 (lpt1, com1 등)을 할당하는 데 사용하는 방법입니다. 이 장치를 처리하는 이름, 일부 깃발 및 "경로"를 전달합니다. 그러나 그것이 당신을 속이게하지 마십시오. 파일 시스템 경로가 아니라 NT 객체 경로입니다. 나는 당신이 그것들을 " device harddisk0"등으로 보았을 것이라고 확신합니다. sysinternals에서 winobj.exe를 사용하여 내가 의미하는 바를 볼 수 있습니다. 어쨌든, 장치 드라이버를 생성 한 다음 MSDOS Symlink를 가리킬 수 있습니다. 그러나 원래의 문제가 무엇인지에 대한 많은 작업처럼 보입니다.

이 Meg to Gigabyte 파일 중 일반적인 디렉토리에는 몇 개의 Meg가 있습니까? 하나의 거대한 파일 내부의 모든 파일을 고수하고 바로 옆에 인덱스 파일 (또는 각 파일의 헤더)을 저장하는 "가상 파일 시스템"파일 내부의 다음 "파일"을 가리키는 것이 가장 좋습니다.

좋은 예는 Microsoft MSN 아카이브 형식을 보는 것입니다. AV 회사에서 일할 때이 아카이브 형식을 취소했으며 실제로는 매우 창의적이지만 매우 간단합니다. 그것은 하나의 파일로 모든 것을 할 수 있고, 당신이 공상을 원한다면, 당신은 할 수 있었다 3 파일에 걸쳐 데이터를 RAID 5 유형 구성에 저장하므로 3 개의 파일 중 하나가 호스가 발생하면 다른 파일을 재건 할 수 있습니다. 또한 사용자는 3 만 볼 수 있습니다 매우 디렉토리의 큰 파일은 개인 (내부) 파일에 액세스 할 수 없습니다.

이 MSN 아카이브 형식 중 하나를 풀리는 코드를 제공했습니다. 코드를 생성하는 코드는 없지만 추출 소스에서 아무런 문제없이 하나를 구성/쓸 수 있습니다. 파일이 삭제 및/또는 자주 이름이 바뀌면 파일의 중고 공간에 문제가 생길 수 있습니다.

이 형식은 CRC 필드도 지원하므로 파일을 확인했는지 테스트 할 수 있습니다. Microsoft가 데이터를 CRC에 사용한 알고리즘을 완전히 뒤집을 수는 없었지만 아주 좋은 생각이 있습니다.

현재 I/O 루틴을 유지할 수는 없습니다. 아카이브 형식.

당신이 그의 도움을 원한다면, 그것은 충분히 큰 문제라면, 아마도 우리는 오프라인으로 이야기하고 당신을위한 해결책을 찾을 수있을 것입니다.

나는 당신에게 fileSystemDriver를 작성하는 것에 반대하지는 않지만,이를 위해서는 보상에 대해 이야기해야합니다. 나는 지금하고있는 것처럼 당신에게 방향과 아이디어를 무료로 제공하게되어 기쁩니다.

여기에 내 이메일 주소를주는 것이 코셔인지 확실하지 않습니다. 우리는 잠재적 인 업무/권유에 대해 이야기 할 수 있기 때문에 So의 정책에 대해 잘 모르겠지만 그것은 나의 유일한 의도는 아닙니다. 차라리 자신의 솔루션을 먼저 찾도록 도와 드리겠습니다.

장치 드라이버를 살펴보기 전에 Winddk를 다운로드하십시오. 여기에는 드라이버 샘플이 있습니다.

내가 왜 이것에 대해 많은 관심을 가지고 있는지 궁금하다면, 나는 이와 비슷한 드라이버를 쓰기 위해 몇 년 동안 슬레이트에 있었기 때문입니다. 그리고 OSX 호환, 사용자는 드라이버를 설치하지 않고 드라이브 볼륨 (USB 키, 탈착식 볼륨)을 보호하거나 복잡한 (그리고 부피가 크고 때로는 성가신) 소프트웨어를 확보 할 수 있습니다. 최근 몇 년 동안 많은 하드웨어 제조업체들이 비슷한 일을 해왔지만 보안이 그다지 안전하다고 생각하지 않습니다. RSA 및 AES, 정확히 GPG 및 PGP 작업을 사용하고 있습니다. 원래 나는 MP3 파일을 보장하는 데 사용 된 것 (내가 믿지만 증거가 없음)에 대해 연락을 취했다. 암호화 된 형식으로 저장되므로 올바른 암호가 없으면 작동하지 않습니다. 그러나 나는 그것에 대한 다른 용도도 보았다. (이것은 16 Meg (예 메그) USB 키 비용이 $ 100 정도가 될 때 돌아 왔습니다).

이 프로젝트는 또한 스마트 카드와 비슷한 것을 사용하고 사용하기 쉽고, 재사용/재발행, 불가능한 (읽기 : 매우 어렵고, 가능성이 낮음) 석유 및 가스 산업 PC 보안 시스템과 함께 진행되었습니다. 나는 집에서 내 아이들에게 그것을 사용할 수있었습니다! (컴퓨터에서 시간을 보내고 누가 가장 많이 얻었는지, 그리고, 그리고, 그리고 ...) 항상 싸우기 때문에 ...)

PHEW .. 여기서 주제를 벗어 났다고 생각합니다. 어쨌든 여기 Microsoft MSN 아카이브 형식의 예입니다. 마스터 파일의 요청 된 파일을 구문 분석/검색 할 때 파일의 오프셋을 따라 파일에 "건너 뛰기"를 항상 "건너 뛰기"할 수 있다는 것을 알고 이와 같은 것을 사용할 수 있는지 확인하십시오. 또는 메모리에 보관 된 미리 정식 데이터에서. 원시 바이너리 파일 데이터를 메모리에로드하지 않기 때문에 유일한 제한은 아마도 32 비트 머신의 4GB 파일 제한 일 것입니다.

Marc (Microsoft MSN 아카이브) 형식은 다음과 같이 (느슨하게) 배치됩니다.

  • 12 바이트 헤더 (단 하나만)
    • 파일 마법
    • 마크 버전
    • 파일 수 (다음 표에서)
  • 68 바이트 파일 테이블 헤더 (1 대 헤더.
    • 파일 이름
    • 파일 크기
    • 체크섬
    • 원시 파일 데이터로 오프셋

이제 12 바이트 파일 테이블 항목에서 파일 길이 및 오프셋에 32 비트가 사용됩니다. 매우 큰 파일의 경우 48 또는 64 비트 정수까지 올라 가야 할 수도 있습니다.

다음은 이것을 처리하기 위해 작성한 몇 가지 코드입니다.

#define MARC_FILE_MAGIC         0x4352414D // In Little Endian
#define MARC_FILENAME_LEN       56 //(You'll notice this is rather small)
#define MARC_HEADER_SIZE        12
#define MARC_FILE_ENT_SIZE      68

#define MARC_DATA_SIZE          1024 * 128 // 128k Read Buffer should be enough.

#define MARC_ERR_OK              0      // No error
#define MARC_ERR_OOD             314    // Out of data error
#define MARC_ERR_OS              315    // Error returned by the OS
#define MARC_ERR_CRC             316    // CRC error

struct marc_file_hdr
{
    ULONG            h_magic;
    ULONG            h_version;
    ULONG            h_files;
    int              h_fd;
    struct marc_dir *h_dir;
};

struct marc_file
{
    char            f_filename[MARC_FILENAME_LEN];
    long            f_filesize;
    unsigned long   f_checksum;
    long            f_offset;
};

struct marc_dir
{
    struct marc_file       *dir_file;
    ULONG                   dir_filenum;
    struct marc_dir        *dir_next;
};

그것은 내가 당신에게 내가 그들을 위해 쓴 헤더에 대한 아이디어를 제공하고, 여기에 열린 기능이 있습니다. 예, 모든 지원 통화, 오류 루틴 등이 누락되었지만 아이디어를 얻습니다. C 및 C ++ 코드 스타일 혼합물을 실례합니다. 우리의 스캐너는 이와 같은 여러 가지 문제의 클러스터였습니다 ... 나는 나머지 코드베이스와 표준을 유지하기 위해 Open (), fopen ()과 같은 골동품 통화를 사용했습니다.

struct marc_file_hdr *marc_open(char *filename)
{
    struct marc_file_hdr *fhdr  = (struct marc_file_hdr*)malloc(sizeof(marc_file_hdr));
    fhdr->h_dir = NULL;

#if defined(_sopen_s)
    int errno = _sopen_s(fhdr->h_fd, filename, _O_BINARY | _O_RDONLY, _SH_DENYWR, _S_IREAD | _S_IWRITE);
#else
    fhdr->h_fd = open(filename, _O_BINARY | _O_RDONLY);
#endif
    if(fhdr->h_fd < 0)
    {
        marc_close(fhdr);
        return NULL;
    }

    //Once we have the file open, read all the file headers, and populate our main headers linked list.
    if(read(fhdr->h_fd, fhdr, MARC_HEADER_SIZE) != MARC_HEADER_SIZE)
    {
        errmsg("MARC: Could not read MARC header from file %s.\n", filename);
        marc_close(fhdr);
        return NULL;
    }

    // Verify the file magic
    if(fhdr->h_magic != MARC_FILE_MAGIC)
    {
        errmsg("MARC: Incorrect file magic %x found in MARC file.", fhdr->h_magic);
        marc_close(fhdr);
        return NULL;
    }

    if(fhdr->h_files <= 0)
    {
        errmsg("MARC: No files found in archive.\n");
        marc_close(fhdr);
        return NULL;
    }

    // Get all the file headers from this archive, and link them to the main header.
    struct marc_dir *lastdir = NULL, *curdir = NULL;
    curdir = (struct marc_dir*)malloc(sizeof(marc_dir));
    fhdr->h_dir = curdir;

    for(int x = 0;x < fhdr->h_files;x++)
    {
        if(lastdir)
        {
            lastdir->dir_next = (struct marc_dir*)malloc(sizeof(marc_dir));
            lastdir->dir_next->dir_next = NULL;
            curdir = lastdir->dir_next;
        }

        curdir->dir_file = (struct marc_file*)malloc(sizeof(marc_file));
        curdir->dir_filenum = x + 1;

        if(read(fhdr->h_fd, curdir->dir_file, MARC_FILE_ENT_SIZE) != MARC_FILE_ENT_SIZE)
        {
            errmsg("MARC: Could not read file header for file %d\n", x);
            marc_close(fhdr);
            return NULL;
        }
        // LEF: Just a little extra insurance...
        curdir->dir_file->f_filename[MARC_FILENAME_LEN] = NULL;

        lastdir = curdir;
    }
    lastdir->dir_next = NULL;

    return fhdr;
}

그런 다음 간단한 추출 방법이 있습니다. 이것은 바이러스 스캐닝을위한 엄격히 의미가 있으므로 검색 루틴이 없습니다. 이것은 단순히 파일을 버리고 스캔 한 후 이동하도록 설계되었습니다. 아래는 Microsoft가 사용했다고 생각하는 CRC 코드 루틴이지만 확실하지 않습니다. 무엇 정확히 그들은 crc'ed. 헤더 데이터 + 파일 데이터 등이 포함될 수 있습니다. 어쨌든 볼 수 있듯이이 아카이브 형식에는 압축이 없지만 매우 추가하기 쉽습니다. 원하는 경우 전체 소스를 제공 할 수 있습니다. (남은 모든 것이 Close () 루틴이고 각 파일을 호출하고 추출하는 코드라고 생각합니다. !!)

bool marc_extract(struct marc_file_hdr *marc, struct marc_file *marcfile, char *file, int &err)
{
    // Create the file from marcfile, in *file's location, return any errors.
    int ofd = 0;
#if defined(_sopen_s)
     err = _sopen_s(ofd, filename, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE);
#else
    ofd = open(file, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR);
#endif

    // Seek to the offset of the file to extract
    if(lseek(marc->h_fd, marcfile->f_offset, SEEK_SET) != marcfile->f_offset)
    {
        errmsg("MARC: Could not seek to offset 0x%04x for file %s.\n", marcfile->f_offset, marcfile->f_filename);
        close(ofd);
        err = MARC_ERR_OS; // Get the last error from the OS.
        return false;
    }

    unsigned char *buffer = (unsigned char*)malloc(MARC_DATA_SIZE);

    long bytesleft = marcfile->f_filesize;
    long readsize = MARC_DATA_SIZE >= marcfile->f_filesize ? marcfile->f_filesize : MARC_DATA_SIZE;
    unsigned long crc = 0;

    while(bytesleft)
    {
        if(read(marc->h_fd, buffer, readsize) != readsize)
        {
            errmsg("MARC: Failed to extract data from MARC archive.\n");
            free(buffer);
            close(ofd);
            err = MARC_ERR_OOD;
            return false;
        }

        crc = marc_checksum(buffer, readsize, crc);

        if(write(ofd, buffer, readsize) != readsize)
        {
            errmsg("MARC: Failed to write data to file.\n");
            free(buffer);
            close(ofd);
            err = MARC_ERR_OS; // Get the last error from the OS.
            return false;
        }
        bytesleft -= readsize;
        readsize = MARC_DATA_SIZE >= bytesleft ? bytesleft : MARC_DATA_SIZE;
    }

    // LEF:  I can't quite figure out how the checksum is computed, but I think it has to do with the file header, PLUS the data in the file, or it's checked on the data in the file
    //       minus any BOM's at the start...  So, we'll just rem out this code for now, but I wrote it anyways.
    //if(crc != marcfile->f_checksum)
    //{
    //    warningmsg("MARC: File CRC does not match.  File could be corrupt, or altered.  CRC=0x%08X, expected 0x%08X\n", crc, marcfile->f_checksum);
    //    err = MARC_ERR_CRC;
    //}

    free(buffer);
    close(ofd);

    return true;
}

여기에 내 가정 된 CRC 루틴이 있습니다 (Stuart Caie와 libmspack, 나는 기억할 수 없다) : :

static unsigned long marc_checksum(void *pv, UINT cb, unsigned long seed)
{
    int count = cb / 4;
    unsigned long csum = seed;
    BYTE *p = (BYTE*)pv;
    unsigned long ul;

    while(count-- > 0)
    {
        ul = *p++;
        ul |= (((unsigned long)(*p++)) <<  8);
        ul |= (((unsigned long)(*p++)) << 16);
        ul |= (((unsigned long)(*p++)) << 24);
        csum ^= ul;
    }

    ul = 0;
    switch(cb % 4)
    {
        case 3: ul |= (((unsigned long)(*p++)) << 16);
        case 2: ul |= (((unsigned long)(*p++)) <<  8);
        case 1: ul |= *p++;
        default: break;
    }
    csum ^= ul;

    return csum;
}                                                                                     

글쎄, 나는이 게시물이 지금 충분히 길다고 생각합니다 ... 도움이 필요하거나 질문이 있으시면 저에게 연락하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top