예제 #1
0
int CFile::Stat(struct stat64* buffer)
{
  if (m_fd == -1)
    return -1;

  struct stat tmpBuffer = {0};

  CLockObject lock(smb);
  int iResult = smbc_fstat(m_fd, &tmpBuffer);

  memset(buffer, 0, sizeof(struct stat64));
  buffer->st_dev = tmpBuffer.st_dev;
  buffer->st_ino = tmpBuffer.st_ino;
  buffer->st_mode = tmpBuffer.st_mode;
  buffer->st_nlink = tmpBuffer.st_nlink;
  buffer->st_uid = tmpBuffer.st_uid;
  buffer->st_gid = tmpBuffer.st_gid;
  buffer->st_rdev = tmpBuffer.st_rdev;
  buffer->st_size = tmpBuffer.st_size;
  buffer->st_atime = tmpBuffer.st_atime;
  buffer->st_mtime = tmpBuffer.st_mtime;
  buffer->st_ctime = tmpBuffer.st_ctime;

  return iResult;
}
예제 #2
0
static int SMB_FSTAT( int fd, struct stat* st )
{
	big_stat s;
	int r = smbc_fstat( fd, &s.st );
	*st = s.st;
	return r;
}
예제 #3
0
파일: fstat_1.c 프로젝트: 0x24bin/winexe-1
int main(int argc, char** argv)
{
	int err = -1;
	int fd = 0;
	struct stat st;

	bzero(g_workgroup,MAX_BUFF_SIZE);

	if ( argc == 4 )
	{
		
		strncpy(g_workgroup,argv[1],strlen(argv[1]));
		strncpy(g_username,argv[2],strlen(argv[2]));
		strncpy(g_password,argv[3],strlen(argv[3]));

		smbc_init(auth_fn, 0);

		fd = 11234;
		err = smbc_fstat(fd,&st);

		if ( err < 0 )
			err = 1;

		else
			err = 0;

		
	}

	return err;

}
예제 #4
0
파일: teststat3.c 프로젝트: AIdrifter/samba
int main(int argc, char* argv[])
{
        int             fd;
        struct stat     st1;
        struct stat     st2;
        char *          pUrl = argv[1];

        if(argc != 2)
        {
                printf("usage: %s <file_url>\n", argv[0]);
                return 1;
        }

        
        smbc_init(get_auth_data_fn, 0);
        
        if (smbc_stat(pUrl, &st1) < 0)
        {
                perror("smbc_stat");
                return 1;
        }
        
        if ((fd = smbc_open(pUrl, O_RDONLY, 0)) < 0)
        {
                perror("smbc_open");
                return 1;
        }

        if (smbc_fstat(fd, &st2) < 0)
        {
                perror("smbc_fstat");
                return 1;
        }
        
        smbc_close(fd);

#define COMPARE(name, field)                                            \
        if (st1.field != st2.field)                                     \
        {                                                               \
                printf("Field " name " MISMATCH: st1=%lu, st2=%lu\n",   \
                       (unsigned long) st1.field,                       \
                       (unsigned long) st2.field);                      \
        }

        COMPARE("st_dev", st_dev);
        COMPARE("st_ino", st_ino);
        COMPARE("st_mode", st_mode);
        COMPARE("st_nlink", st_nlink);
        COMPARE("st_uid", st_uid);
        COMPARE("st_gid", st_gid);
        COMPARE("st_rdev", st_rdev);
        COMPARE("st_size", st_size);
        COMPARE("st_blksize", st_blksize);
        COMPARE("st_blocks", st_blocks);
        COMPARE("st_atime", st_atime);
        COMPARE("st_mtime", st_mtime);
        COMPARE("st_ctime", st_ctime);

        return 0;
}
예제 #5
0
파일: main.cpp 프로젝트: aont/smbcfs
static int smbcfs_fgetattr(const char* const path, struct stat* const stbuf, struct fuse_file_info* const fi)
{

  const int fh = fi->fh;

#ifdef MUTEX_LOCK
  pthread_mutex_lock(&mutex_lock);  
#endif

  const int ret_fstat = smbc_fstat(fh, stbuf);

#ifdef MUTEX_LOCK
  pthread_mutex_unlock(&mutex_lock);  
#endif

#ifdef SMBCFS_DEBUG
  fprintf(stderr, "[smbc_fstat] %d %p => %d\n", fh, stbuf, ret_fstat);
#endif
  return ret_fstat;
}
예제 #6
0
int smb_download_file(const char *base, const char *name, int recursive, int resume, char *outfile) {
	int remotehandle, localhandle;
	time_t start_time = time(NULL);
	const char *newpath;
	char path[SMB_MAXPATHLEN];
	char checkbuf[2][RESUME_CHECK_SIZE];
	char *readbuf = NULL;
	off_t offset_download = 0, offset_check = 0, curpos = 0, start_offset = 0;
	struct stat localstat, remotestat;

	snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (*base && *name && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);
	
	remotehandle = smbc_open(path, O_RDONLY, 0755);

	if(remotehandle < 0) {
		switch(errno) {
		case EISDIR: 
			if(!recursive) {
				fprintf(stderr, "%s is a directory. Specify -R to download recursively\n", path);
				return 0;
			}
			smb_download_dir(base, name, resume);
			return 0;

		case ENOENT:
			fprintf(stderr, "%s can't be found on the remote server\n", path);
			return 0;

		case ENOMEM:
			fprintf(stderr, "Not enough memory\n");
			exit(1);
			return 0;

		case ENODEV:
			fprintf(stderr, "The share name used in %s does not exist\n", path);
			return 0;

		case EACCES:
			fprintf(stderr, "You don't have enough permissions to access %s\n", path);
			return 0;

		default:
			perror("smbc_open");
			return 0;
		}
	} 

	if(smbc_fstat(remotehandle, &remotestat) < 0) {
		fprintf(stderr, "Can't stat %s: %s\n", path, strerror(errno));
		return 0;
	}

	if(outfile) newpath = outfile;
	else if(!name[0]) {
		newpath = strrchr(base, '/');
		if(newpath)newpath++; else newpath = base;
	} else newpath = name;

	if(newpath[0] == '/')newpath++;
	
	/* Open local file and, if necessary, resume */
	localhandle = open(newpath, O_CREAT | O_NONBLOCK | O_RDWR | (!resume?O_EXCL:0), 0755);
	if(localhandle < 0) {
		fprintf(stderr, "Can't open %s: %s\n", newpath, strerror(errno));
		smbc_close(remotehandle);
		return 0;
	}
	
	fstat(localhandle, &localstat);

	start_offset = localstat.st_size;

	if(localstat.st_size && localstat.st_size == remotestat.st_size) {
		if(verbose)fprintf(stderr, "%s is already downloaded completely.\n", path);
		else if(!quiet)fprintf(stderr, "%s\n", path);
		smbc_close(remotehandle);
		close(localhandle);
		return 1;
	}

	if(localstat.st_size > RESUME_CHECK_OFFSET && remotestat.st_size > RESUME_CHECK_OFFSET) {
		offset_download = localstat.st_size - RESUME_DOWNLOAD_OFFSET;
		offset_check = localstat.st_size - RESUME_CHECK_OFFSET;
		if(verbose)printf("Trying to start resume of %s at "OFF_T_FORMAT"\n"
			   "At the moment "OFF_T_FORMAT" of "OFF_T_FORMAT" bytes have been retrieved\n", newpath, offset_check, 
			   localstat.st_size, remotestat.st_size);
	}

	if(offset_check) { 
		off_t off1, off2;
		/* First, check all bytes from offset_check to offset_download */
		off1 = lseek(localhandle, offset_check, SEEK_SET);
		if(off1 < 0) {
			fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in local file %s\n", offset_check, newpath);
			smbc_close(remotehandle); close(localhandle);
			return 0;
		}

		off2 = smbc_lseek(remotehandle, offset_check, SEEK_SET); 
		if(off2 < 0) {
			fprintf(stderr, "Can't seek to "OFF_T_FORMAT" in remote file %s\n", offset_check, newpath);
			smbc_close(remotehandle); close(localhandle);
			return 0;
		}

		if(off1 != off2) {
			fprintf(stderr, "Offset in local and remote files is different (local: "OFF_T_FORMAT", remote: "OFF_T_FORMAT")\n", off1, off2);
			return 0;
		}

		if(smbc_read(remotehandle, checkbuf[0], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
			fprintf(stderr, "Can't read %d bytes from remote file %s\n", RESUME_CHECK_SIZE, path);
			smbc_close(remotehandle); close(localhandle);
			return 0;
		}

		if(read(localhandle, checkbuf[1], RESUME_CHECK_SIZE) != RESUME_CHECK_SIZE) {
			fprintf(stderr, "Can't read %d bytes from local file %s\n", RESUME_CHECK_SIZE, name);
			smbc_close(remotehandle); close(localhandle);
			return 0;
		}

		if(memcmp(checkbuf[0], checkbuf[1], RESUME_CHECK_SIZE) == 0) {
			if(verbose)printf("Current local and remote file appear to be the same. Starting download from offset "OFF_T_FORMAT"\n", offset_download);
		} else {
			fprintf(stderr, "Local and remote file appear to be different, not doing resume for %s\n", path);
			smbc_close(remotehandle); close(localhandle);
			return 0;
		}
	}

	readbuf = malloc(blocksize);

	/* Now, download all bytes from offset_download to the end */
	for(curpos = offset_download; curpos < remotestat.st_size; curpos+=blocksize) {
		ssize_t bytesread = smbc_read(remotehandle, readbuf, blocksize);
		if(bytesread < 0) {
			fprintf(stderr, "Can't read %d bytes at offset "OFF_T_FORMAT", file %s\n", blocksize, curpos, path);
			smbc_close(remotehandle); close(localhandle);
			free(readbuf);
			return 0;
		}

		total_bytes += bytesread;

		if(write(localhandle, readbuf, bytesread) < 0) {
			fprintf(stderr, "Can't write %d bytes to local file %s at offset "OFF_T_FORMAT"\n", bytesread, path, curpos);
			free(readbuf);
			smbc_close(remotehandle); close(localhandle);
			return 0;
		}

		if(dots)fputc('.', stderr);
		else if(!quiet) {
			print_progress(newpath, start_time, time(NULL), start_offset, curpos, remotestat.st_size);
		}
	}

	free(readbuf);

	if(dots){
		fputc('\n', stderr);
		printf("%s downloaded\n", path);
	} else if(!quiet) {
		int i;
		fprintf(stderr, "\r%s", path);
		if(columns) {
			for(i = strlen(path); i < columns; i++) {
				fputc(' ', stderr);
			}
		}
		fputc('\n', stderr);
	}

	if(keep_permissions) {
		if(fchmod(localhandle, remotestat.st_mode) < 0) {
			fprintf(stderr, "Unable to change mode of local file %s to %o\n", path, remotestat.st_mode);
			smbc_close(remotehandle);
			close(localhandle);
			return 0;
		}
	}
	smbc_close(remotehandle);
	close(localhandle);
	return 1;
}
예제 #7
0
int smb_download_dir(const char *base, const char *name, int resume)
{
	char path[SMB_MAXPATHLEN];
	int dirhandle;
	struct smbc_dirent *dirent;
	const char *relname = name;
	char *tmpname;
	struct stat remotestat;
	snprintf(path, SMB_MAXPATHLEN-1, "%s%s%s", base, (base[0] && name[0] && name[0] != '/' && base[strlen(base)-1] != '/')?"/":"", name);

	/* List files in directory and call smb_download_file on them */
	dirhandle = smbc_opendir(path);
	if(dirhandle < 1) {
		if(errno == ENOTDIR) return smb_download_file(base, name, 1, resume, NULL);
		fprintf(stderr, "Can't open directory %s: %s\n", path, strerror(errno));
		return 0;
	}

	while(*relname == '/')relname++;
	mkdir(relname, 0755);
	
	tmpname = strdup(name);

	while((dirent = smbc_readdir(dirhandle))) {
		char *newname;
		if(!strcmp(dirent->name, ".") || !strcmp(dirent->name, ".."))continue;
		asprintf(&newname, "%s/%s", tmpname, dirent->name);
		switch(dirent->smbc_type) {
		case SMBC_DIR:
			smb_download_dir(base, newname, resume);
			break;

		case SMBC_WORKGROUP:
			smb_download_dir("smb://", dirent->name, resume);
			break;

		case SMBC_SERVER:
			smb_download_dir("smb://", dirent->name, resume);
			break;

		case SMBC_FILE:
			smb_download_file(base, newname, 1, resume, NULL);
			break;

		case SMBC_FILE_SHARE:
			smb_download_dir(base, newname, resume);
			break;

		case SMBC_PRINTER_SHARE:
			if(!quiet)printf("Ignoring printer share %s\n", dirent->name);
			break;

		case SMBC_COMMS_SHARE:
			if(!quiet)printf("Ignoring comms share %s\n", dirent->name);
			break;
			
		case SMBC_IPC_SHARE:
			if(!quiet)printf("Ignoring ipc$ share %s\n", dirent->name);
			break;

		default:
			fprintf(stderr, "Ignoring file '%s' of type '%d'\n", newname, dirent->smbc_type);
			break;
		}
		free(newname);
	}
	free(tmpname);

	if(keep_permissions) {
		if(smbc_fstat(dirhandle, &remotestat) < 0) {
			fprintf(stderr, "Unable to get stats on %s on remote server\n", path);
			smbc_closedir(dirhandle);
			return 0;
		}
		
		if(chmod(relname, remotestat.st_mode) < 0) {
			fprintf(stderr, "Unable to change mode of local dir %s to %o\n", relname, remotestat.st_mode);
			smbc_closedir(dirhandle);
			return 0;
		}
	}

	smbc_closedir(dirhandle);
	return 1;
}
예제 #8
0
int main(int argc, char *argv[])
{
  int err, fd, dh1, dsize, dirc;
  const char *file = "smb://samba/public/testfile.txt";
  const char *file2 = "smb://samba/public/testfile2.txt";
  char buff[256];
  char dirbuf[512];
  char *dirp;
  struct stat st1, st2;

  err = smbc_init(get_auth_data_fn,  10); /* Initialize things */

  if (err < 0) {

    fprintf(stderr, "Initializing the smbclient library ...: %s\n", strerror(errno));

  }

  if (argc > 1) {

    if ((dh1 = smbc_opendir(argv[1]))<1) {

      fprintf(stderr, "Could not open directory: %s: %s\n",
	      argv[1], strerror(errno));

      exit(1);

    }

    fprintf(stdout, "Directory handle: %u\n", dh1);

    /* Now, list those directories, but in funny ways ... */

    dirp = (char *)dirbuf;

    if ((dirc = smbc_getdents(dh1, (struct smbc_dirent *)dirp, 
			      sizeof(dirbuf))) < 0) {

      fprintf(stderr, "Problems getting directory entries: %s\n",
	      strerror(errno));

      exit(1);

    }

    /* Now, process the list of names ... */

    fprintf(stdout, "Directory listing, size = %u\n", dirc);

    while (dirc > 0) {

      dsize = ((struct smbc_dirent *)dirp)->dirlen;
      fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
	      ((struct smbc_dirent *)dirp)->smbc_type, 
	      ((struct smbc_dirent *)dirp)->name, 
	      ((struct smbc_dirent *)dirp)->comment);

      dirp += dsize;
      dirc -= dsize;

    }

    dirp = (char *)dirbuf;

    exit(1);

  }

  /* For now, open a file on a server that is hard coded ... later will
   * read from the command line ...
   */

  fd = smbc_open(file, O_RDWR | O_CREAT | O_TRUNC, 0666);

  if (fd < 0) {

    fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
    exit(0);

  }

  fprintf(stdout, "Opened or created file: %s\n", file);

  /* Now, write some date to the file ... */

  memset(buff, '\0', sizeof(buff));
  snprintf(buff, sizeof(buff), "%s", "Some test data for the moment ...");

  err = smbc_write(fd, buff, sizeof(buff));

  if (err < 0) {
    
    fprintf(stderr, "writing file: %s: %s\n", file, strerror(errno));
    exit(0);

  }

  fprintf(stdout, "Wrote %lu bytes to file: %s\n",
          (unsigned long) sizeof(buff), buff);

  /* Now, seek the file back to offset 0 */

  err = smbc_lseek(fd, SEEK_SET, 0);

  if (err < 0) {

    fprintf(stderr, "Seeking file: %s: %s\n", file, strerror(errno));
    exit(0);

  }

  fprintf(stdout, "Completed lseek on file: %s\n", file);

  /* Now, read the file contents back ... */

  err = smbc_read(fd, buff, sizeof(buff));

  if (err < 0) {

    fprintf(stderr, "Reading file: %s: %s\n", file, strerror(errno));
    exit(0);

  }

  fprintf(stdout, "Read file: %s\n", buff);  /* Should check the contents */

  fprintf(stdout, "Now fstat'ing file: %s\n", file);

  err = smbc_fstat(fd, &st1);

  if (err < 0) {

    fprintf(stderr, "Fstat'ing file: %s: %s\n", file, strerror(errno));
    exit(0);

  }


  /* Now, close the file ... */

  err = smbc_close(fd);

  if (err < 0) {

    fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));

  }

  /* Now, rename the file ... */

  err = smbc_rename(file, file2);

  if (err < 0) {

    fprintf(stderr, "Renaming file: %s to %s: %s\n", file, file2, strerror(errno));

  }

  fprintf(stdout, "Renamed file %s to %s\n", file, file2);

  /* Now, create a file and delete it ... */

  fprintf(stdout, "Now, creating file: %s so we can delete it.\n", file);

  fd = smbc_open(file, O_RDWR | O_CREAT, 0666);

  if (fd < 0) {

    fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
    exit(0);

  }

  fprintf(stdout, "Opened or created file: %s\n", file);

  err = smbc_close(fd);

  if (err < 0) {

    fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));
    exit(0);

  }
  
  /* Now, delete the file ... */

  fprintf(stdout, "File %s created, now deleting ...\n", file);

  err = smbc_unlink(file);

  if (err < 0) {

    fprintf(stderr, "Deleting file: %s: %s\n", file, strerror(errno));
    exit(0);

  }

  /* Now, stat the file, file 2 ... */

  fprintf(stdout, "Now stat'ing file: %s\n", file);

  err = smbc_stat(file2, &st2);

  if (err < 0) {

    fprintf(stderr, "Stat'ing file: %s: %s\n", file, strerror(errno));
    exit(0);

  }

  fprintf(stdout, "Stat'ed file:   %s. Size = %d, mode = %04X\n", file2, 
	  (int)st2.st_size, (unsigned int)st2.st_mode);
  fprintf(stdout, "    time: %s\n", ctime(&st2.st_atime));
  fprintf(stdout, "Earlier stat:   %s, Size = %d, mode = %04X\n", file, 
	  (int)st1.st_size, (unsigned int)st1.st_mode);
  fprintf(stdout, "    time: %s\n", ctime(&st1.st_atime));

  /* Now, make a directory ... */

  fprintf(stdout, "Making directory smb://samba/public/make-dir\n");

  if (smbc_mkdir("smb://samba/public/make-dir", 0666) < 0) {

    fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n", 
	    strerror(errno));

    if (errno == EEXIST) { /* Try to delete the directory */

      fprintf(stdout, "Trying to delete directory: smb://samba/public/make-dir\n");

      if (smbc_rmdir("smb://samba/public/make-dir") < 0) { /* Error */

	fprintf(stderr, "Error removing directory: smb://samba/public/make-dir: %s\n", strerror(errno));

	exit(0);

      }

      fprintf(stdout, "Making directory: smb://samba/public/make-dir\n");

      if (smbc_mkdir("smb://samba/public/make-dir", 666) < 0) {

	fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n",
		strerror(errno));

	fprintf(stderr, "I give up!\n");

	exit(1);

      }

    }

    exit(0);
    
  }

  fprintf(stdout, "Made dir: make-dir\n");
  return 0;
}
예제 #9
0
파일: smb.c 프로젝트: AsamQi/vlc
/****************************************************************************
 * Open: connect to smb server and ask for file
 ****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys;
    struct stat  filestat;
    char         *psz_location, *psz_uri;
    char         *psz_user = NULL, *psz_pwd = NULL, *psz_domain = NULL;
    int          i_ret;
    int          i_smb;

    /* Parse input URI
     * [[[domain;]user[:password@]]server[/share[/path[/file]]]] */
    psz_location = strchr( p_access->psz_location, '/' );
    if( !psz_location )
    {
        msg_Err( p_access, "invalid SMB URI: smb://%s", psz_location );
        return VLC_EGENERIC;
    }
    else
    {
        char *psz_tmp = strdup( p_access->psz_location );
        char *psz_parser;

        psz_tmp[ psz_location - p_access->psz_location ] = 0;
        psz_location = p_access->psz_location;
        psz_parser = strchr( psz_tmp, '@' );
        if( psz_parser )
        {
            /* User info is there */
            *psz_parser = 0;
            psz_location = p_access->psz_location + (psz_parser - psz_tmp) + 1;

            psz_parser = strchr( psz_tmp, ':' );
            if( psz_parser )
            {
                /* Password found */
                psz_pwd = strdup( psz_parser+1 );
                *psz_parser = 0;
            }

            psz_parser = strchr( psz_tmp, ';' );
            if( psz_parser )
            {
                /* Domain found */
                *psz_parser = 0; psz_parser++;
                psz_domain = strdup( psz_tmp );
            }
            else psz_parser = psz_tmp;

            psz_user = strdup( psz_parser );
        }

        free( psz_tmp );
    }

    /* Build an SMB URI
     * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] */

    if( !psz_user ) psz_user = var_InheritString( p_access, "smb-user" );
    if( psz_user && !*psz_user ) { free( psz_user ); psz_user = NULL; }
    if( !psz_pwd ) psz_pwd = var_InheritString( p_access, "smb-pwd" );
    if( psz_pwd && !*psz_pwd ) { free( psz_pwd ); psz_pwd = NULL; }
    if( !psz_domain ) psz_domain = var_InheritString( p_access, "smb-domain" );
    if( psz_domain && !*psz_domain ) { free( psz_domain ); psz_domain = NULL; }

#ifdef _WIN32
    if( psz_user )
        Win32AddConnection( p_access, psz_location, psz_user, psz_pwd, psz_domain);
    i_ret = asprintf( &psz_uri, "//%s", psz_location );
#else
    if( psz_user )
        i_ret = asprintf( &psz_uri, "smb://%s%s%s%s%s@%s",
                          psz_domain ? psz_domain : "", psz_domain ? ";" : "",
                          psz_user, psz_pwd ? ":" : "",
                          psz_pwd ? psz_pwd : "", psz_location );
    else
        i_ret = asprintf( &psz_uri, "smb://%s", psz_location );
#endif

    free( psz_user );
    free( psz_pwd );
    free( psz_domain );

    if( i_ret == -1 )
        return VLC_ENOMEM;

#ifndef _WIN32
    if( smbc_init( smb_auth, 0 ) )
    {
        free( psz_uri );
        return VLC_EGENERIC;
    }
#endif

/*
** some version of glibc defines open as a macro, causing havoc
** with other macros using 'open' under the hood, such as the
** following one:
*/
#if defined(smbc_open) && defined(open)
# undef open
#endif
    if( (i_smb = smbc_open( psz_uri, O_RDONLY, 0 )) < 0 )
    {
        msg_Err( p_access, "open failed for '%s' (%m)",
                 p_access->psz_location );
        free( psz_uri );
        return VLC_EGENERIC;
    }

    /* Init p_access */
    STANDARD_READ_ACCESS_INIT;

    i_ret = smbc_fstat( i_smb, &filestat );
    if( i_ret )
    {
        errno = i_ret;
        msg_Err( p_access, "stat failed (%m)" );
    }
    else
        p_sys->size = filestat.st_size;

    free( psz_uri );

    p_sys->i_smb = i_smb;

    return VLC_SUCCESS;
}
예제 #10
0
파일: smb2.c 프로젝트: Efreak/elinks
static void
do_smb(struct connection *conn)
{
	struct uri *uri = conn->uri;
	struct auth_entry *auth = find_auth(uri);
	struct string string;
	unsigned char *url;
	int dir;

	if ((uri->userlen && uri->passwordlen) || !auth) {
		url = get_uri_string(uri, URI_BASE);
	} else {
		unsigned char *uri_string = get_uri_string(uri, URI_HOST | URI_PORT | URI_DATA);

		if (!uri_string || !init_string(&string)) {
			smb_error(connection_state(S_OUT_OF_MEM));
		}
		/* Must URI-encode the username and password to avoid
		 * ambiguity if they contain "/:@" characters.
		 * Libsmbclient then decodes them again, and the
		 * server gets them as they were in auth->user and
		 * auth->password, i.e. as the user typed them in the
		 * auth dialog.  This implies that, if the username or
		 * password contains some characters or bytes that the
		 * user cannot directly type, then she cannot enter
		 * them.  If that becomes an actual problem, it should
		 * be fixed in the auth dialog, e.g. by providing a
		 * hexadecimal input mode.  */
		add_to_string(&string, "smb://");
		encode_uri_string(&string, auth->user, -1, 1);
		add_char_to_string(&string, ':');
		encode_uri_string(&string, auth->password, -1, 1);
		add_char_to_string(&string, '@');
		add_to_string(&string, uri_string);
		url = string.source;
	}

	if (!url) {
		smb_error(connection_state(S_OUT_OF_MEM));
	}
	if (smbc_init(smb_auth, 0)) {
		smb_error(connection_state_for_errno(errno));
	};


	dir = smbc_opendir(url);
	if (dir >= 0) {
		struct string prefix;

		init_string(&prefix);
		add_to_string(&prefix, url);
		add_char_to_string(&prefix, '/');
		smb_directory(dir, &prefix, conn->uri);
		done_string(&prefix);
	} else {
		const int errno_from_opendir = errno;
		char buf[READ_SIZE];
		struct stat sb;
		int r, res, fdout;
		int file = smbc_open(url, O_RDONLY, 0);

		if (file < 0) {
			/* If we're opening the list of shares without
			 * proper authentication, then smbc_opendir
			 * fails with EACCES and smbc_open fails with
			 * ENOENT.  In this case, return the EACCES so
			 * that the parent ELinks process will prompt
			 * for credentials.  */
			if (errno == ENOENT && errno_from_opendir == EACCES)
				errno = errno_from_opendir;
			smb_error(connection_state_for_errno(errno));
		}

		res = smbc_fstat(file, &sb);
		if (res) {
			smb_error(connection_state_for_errno(res));
		}
		/* filesize */
		fprintf(header_out, "%" OFF_PRINT_FORMAT,
			(off_print_T) sb.st_size);
		fclose(header_out);

		fdout = fileno(data_out);
		while ((r = smbc_read(file, buf, READ_SIZE)) > 0) {
			if (safe_write(fdout, buf, r) <= 0)
					break;
		}
		smbc_close(file);
		exit(0);
	}
}